cctally 1.115.0 → 1.116.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.
- package/CHANGELOG.md +16 -0
- package/bin/_cctally_cache.py +85 -4
- package/bin/_cctally_completion.py +80 -12
- package/bin/_cctally_core.py +106 -9
- package/bin/_cctally_dashboard.py +6 -9
- package/bin/_cctally_dashboard_envelope.py +26 -32
- package/bin/_cctally_db.py +85 -4
- package/bin/_cctally_doctor.py +38 -5
- package/bin/_cctally_five_hour.py +83 -1017
- package/bin/_cctally_journal.py +1307 -180
- package/bin/_cctally_journal_repair.py +9 -7
- package/bin/_cctally_oauth_samples.py +280 -0
- package/bin/_cctally_parser.py +5 -0
- package/bin/_cctally_quarantine.py +14 -4
- package/bin/_cctally_quota.py +70 -8
- package/bin/_cctally_quota_model.py +35 -4
- package/bin/_cctally_record.py +414 -123
- package/bin/_cctally_rederive.py +632 -235
- package/bin/_cctally_refresh.py +29 -0
- package/bin/_cctally_statusline.py +984 -47
- package/bin/_cctally_store.py +972 -58
- package/bin/_cctally_tui.py +62 -7
- package/bin/_cctally_update.py +25 -0
- package/bin/_lib_account_protocol.py +201 -18
- package/bin/_lib_clone_copy.py +46 -11
- package/bin/_lib_dashboard_sources.py +57 -15
- package/bin/_lib_detector_access_registry.py +273 -52
- package/bin/_lib_doctor.py +302 -1
- package/bin/_lib_journal.py +145 -25
- package/bin/_lib_journal_router.py +166 -48
- package/bin/_lib_oauth_samples.py +238 -0
- package/bin/_lib_pricing_check.py +0 -12
- package/bin/_lib_provider_activity.py +770 -0
- package/bin/_lib_quarantine.py +3 -2
- package/bin/_lib_quota_model.py +96 -6
- package/bin/_lib_rebuild_progress.py +146 -0
- package/bin/_lib_record.py +22 -0
- package/bin/_lib_rederive.py +299 -3
- package/bin/_lib_snapshot_cache.py +43 -1
- package/bin/_lib_stale_proof.py +708 -0
- package/bin/_lib_statusline_candidates.py +65 -5
- package/bin/_lib_worker_launches.py +315 -0
- package/bin/cctally +6 -11
- package/dashboard/static/assets/{ConversationsView-Bc8LCOAZ.js → ConversationsView-Dflb_myA.js} +1 -1
- package/dashboard/static/assets/DoctorModal-DFX5CfIs.js +1 -0
- package/dashboard/static/assets/{ModalRoot-DLPgyAM_.js → ModalRoot-HlxoagIa.js} +1 -1
- package/dashboard/static/assets/{ProjectsDrillPanel-z53a4v4M.js → ProjectsDrillPanel-C3PJy1xx.js} +1 -1
- package/dashboard/static/assets/{SourceDetailModal-Bw0T8W-W.js → SourceDetailModal-BczsWKhD.js} +1 -1
- package/dashboard/static/assets/{UpdateModal-D5AKx4Yw.js → UpdateModal-Os-Lo5cs.js} +1 -1
- package/dashboard/static/assets/{index-BXDOzSng.js → index-CYZ3NLqF.js} +3 -3
- package/dashboard/static/assets/{outlineNavigation-JObY7cUY.js → outlineNavigation-k-zIif6W.js} +1 -1
- package/dashboard/static/dashboard.html +1 -1
- package/package.json +7 -2
- package/bin/_lib_merge_gate.py +0 -452
- package/dashboard/static/assets/DoctorModal-D--qVBwe.js +0 -1
package/dashboard/static/assets/{outlineNavigation-JObY7cUY.js → outlineNavigation-k-zIif6W.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{Ft as e,Rt as t,_t as n,ft as r,ht as i}from"./useKeymap-CW7Up0Ay.js";import{Ft as a}from"./index-BXDOzSng.js";var o=t(e(),1),s=class extends Error{status;constructor(e){super(`HTTP ${e}`),this.status=e,this.name=`HttpError`}};function c(e){return e?.name===`AbortError`}async function l(e,t){let n=await fetch(e,t?{signal:t}:void 0);if(!n.ok)throw new s(n.status);return await n.json()}function u(e){let t=e?.data_version;return typeof t==`string`&&t!==``?t:e?.generated_at??``}var d={legacy_bridge_pending:{reason:`legacy_bridge_pending`,message:`Transcripts have not finished moving into the conversation store. Run cctally cache-sync to finish the import.`,retryable:!1},maintenance:{reason:`maintenance`,message:`The conversation store is busy with maintenance. Conversations return once it finishes.`,retryable:!0},schema_behind:{reason:`schema_behind`,message:`The conversation store is behind this version of cctally. Run cctally cache-sync to bring it up to date.`,retryable:!1},schema_ahead:{reason:`schema_ahead`,message:`The conversation store was written by a newer version of cctally. Update cctally to read it.`,retryable:!1}},f={reason:`unavailable`,message:`The conversation store is not available right now.`,retryable:!0};function p(e){if(typeof e!=`object`||!e)return null;let t=e;return t.status===`degraded`?typeof t.degraded_reason==`string`&&t.degraded_reason?t.degraded_reason:f.reason:null}function m(e){return d[e]??{...f,reason:e||f.reason}}function h(e,t,n){n!==void 0&&e.append(t,String(n))}function g(e,t={}){let n=new URLSearchParams;return n.append(`source`,e),h(n,`account`,t.accountKey),h(n,`project_key`,t.projectKey),h(n,`model`,t.model),h(n,`limit`,t.limit),h(n,`cursor`,t.cursor),h(n,`selected`,t.selected),`/api/conversations?${n.toString()}`}function _(e,t){let n=new URLSearchParams({source:e});return h(n,`account`,t),`/api/conversations/facets?${n.toString()}`}function v(e,t){let n=new URLSearchParams;return n.append(`source`,e),h(n,`account`,t.accountKey),n.append(`q`,t.query),h(n,`kind`,t.kind),h(n,`limit`,t.limit),h(n,`cursor`,t.cursor),`/api/conversation/search?${n.toString().replace(/\+/g,`%20`)}`}var y={detail:``,outline:`/outline`,find:`/find`,prompts:`/prompts`,payload:`/payload`,export:`/export`,"anon-map":`/anon-map`,events:`/events`,media:`/media`};function b(e,t,r){let i=n(e);if(i.source===`codex`&&!i.key.startsWith(`v1.`))throw Error(`Codex conversation keys must be qualified`);let a=new URLSearchParams;h(a,`account`,i.account_key);for(let[e,t]of Object.entries(r??{}))t!==void 0&&a.append(e,typeof t==`boolean`?t?`1`:`0`:String(t));let o=a.size?`?${a.toString().replace(/\+/g,`%20`)}`:``;return`/api/conversation/${encodeURIComponent(i.key)}${y[t]}${o}`}function x(e){let t=e.native_card;return t?.type===`session_ref`?t.scope===`shell`&&t.ref!=null?[t.ref]:[]:t?.type===`program`?t.invocations.flatMap(e=>e.kind===`session`&&e.scope===`shell`&&e.ref!=null?[e.ref]:[]):[]}function S(e,t){return t==null?``:e===`shell`?`session ${t}`:`cell ${t}`}function C(e,t){return t==null?``:e===`shell`?`s${t}`:`c${t}`}function w(e){return e===`write`?`wrote to`:`polled`}function T(e){return e===`write`?`wrote`:`poll`}var E=60;function D(e){let t=e.replace(/\s+/g,` `).trim();return t.length>E?`${t.slice(0,E)}…`:t}function O(e){let t=new Set(e.flatMap(e=>x(e)));return t.size===1?[...t][0]:null}function k(e,t,n,r){if(!e||t!==`shell`||n==null)return`silent`;let i=e.sessions[n];return i?.opener_block_key==null?e.truncated?`index_truncated`:`not_retained`:r!=null&&r===i.opener_block_key?`opener`:`silent`}function A(e){return new Set(e.map(e=>e.parent_uuid))}function j(e){let t=new Map;for(let n of e){let e=t.get(n.parent_uuid);e?e.push(n):t.set(n.parent_uuid,[n])}return t}function M(e){return e.kind===`reasoning`?e.landmark_key:e.block_key}var N={tool_error:`error`,plan:`plan`,reasoning:`heading`};function P(e,t){if(!t?.length)return[];let n=j(t),r=[];return e.forEach((e,t)=>{for(let i of n.get(e.uuid)??[])r.push({landmark:i,ownerTurnIndex:t})}),r}var F=class extends Error{constructor(){super(`Conversation indexing is still finishing.`)}},I=class extends Error{reason;constructor(e){let t=m(e);super(t.message),this.name=`ConversationDegraded`,this.reason=t.reason}};function L(e){return typeof e==`number`&&Number.isFinite(e)?e:0}function ee(e){return typeof e==`number`&&Number.isFinite(e)?e:null}function R(e){if(e)return e.source===`codex`||`cached_input`in e||`reasoning_output`in e?{source:`codex`,input:L(e.input),output:L(e.output),cache_creation:0,cache_read:0,cached_input:L(e.cached_input),reasoning_output:L(e.reasoning_output)}:{source:`claude`,input:L(e.input),output:L(e.output),cache_creation:L(e.cache_creation??e.cache_create),cache_read:L(e.cache_read)}}function te(e){let t=2166136261;for(let n=0;n<e.length;n++)t^=e.charCodeAt(n),t=Math.imul(t,16777619);return t>>>0||1}function z(e){if(typeof e!=`string`||e.trim()===``)return null;try{let t=JSON.parse(e);return t&&typeof t==`object`&&!Array.isArray(t)?t:{value:t}}catch{return{raw:e}}}var ne=new Set([`create_branch`,`stage`,`commit`,`push`,`create_pr`]);function B(e){return typeof e==`string`&&e.trim()!==``?e.trim():void 0}function re(e){if(!Array.isArray(e)||e.length===0)return;let t=[];for(let n of e){let e=V(n);if(!e||typeof e.key!=`string`||typeof e.text!=`string`)return;t.push({key:e.key,text:e.text})}return t}function ie(e){let t=V(e.detail?.reasoning);if(t?.schema_version===1){let n=B(t.title),r=B(t.summary),i=B(t.body);if(!n&&!r&&!i)return null;let a=re(t.headings);return{kind:`codex_reasoning`,source:B(t.source)??`codex`,title:n,summary:r,body:i,...a?{headings:a}:{},...e.block_key?{block_key:e.block_key}:{}}}let n=B(e.text);return n?{kind:`codex_reasoning`,source:`codex`,body:n,...e.block_key?{block_key:e.block_key}:{}}:null}function ae(e){if(!Array.isArray(e)||e.length===0)return null;let t=[];for(let n of e){let e=V(n);if(!e||e.schema_version!==1)return null;if(e.type===`git`&&typeof e.action==`string`&&ne.has(e.action)){t.push({type:`git`,action:e.action,...e.action===`create_pr`&&typeof e.draft==`boolean`?{draft:e.draft}:{}});continue}if(e.type===`memory_citation`&&Number.isSafeInteger(e.citation_count)&&Number(e.citation_count)>=0&&Number.isSafeInteger(e.rollout_count)&&Number(e.rollout_count)>=0){t.push({type:`memory_citation`,citation_count:Number(e.citation_count),rollout_count:Number(e.rollout_count)});continue}return null}return t}function oe(e){let t=V(e.detail?.lifecycle);return t?.schema_version!==1||t.event!==`task_started`&&t.event!==`task_complete`?null:{kind:`codex_lifecycle`,event:t.event,...B(t.message)?{message:B(t.message)}:{},...B(t.error)?{error:B(t.error)}:{},...typeof t.duration_ms==`number`&&Number.isFinite(t.duration_ms)?{duration_ms:t.duration_ms}:{},...e.block_key?{payload_key:e.block_key}:{}}}function V(e){return typeof e==`object`&&e&&!Array.isArray(e)?e:null}function se(e){if(!Array.isArray(e))return null;let t=[];for(let n of e){let e=V(n);if(!e)return null;let r={};for(let t of[`path`,`move_path`,`status`])typeof e[t]==`string`&&(r[t]=e[t]);t.push(r)}return t}function ce(e){if(!Array.isArray(e))return null;let t=[];for(let n of e){let e=V(n);if(!e)return null;let r={};for(let t of[`path`,`move_path`,`status`,`unified_diff`,`raw`,`raw_extra`])typeof e[t]==`string`&&(r[t]=e[t]);typeof e.truncated==`boolean`&&(r.truncated=e.truncated),(e.diff_source===`retained`||e.diff_source===`derived`)&&(r.diff_source=e.diff_source),t.push(r)}return t}function H(e){let t=V(e);if(t?.schema_version!==1||t.type!==`terminal_output`||!Array.isArray(t.parts))return;let n=t.parts.map(e=>{let t=V(e);if(!t||t.type!==`text`&&t.type!==`raw`||typeof t.text!=`string`)return null;let n=t.stream===`stdout`||t.stream===`stderr`?t.stream:`output`;return{type:t.type,stream:n,text:t.text}});if(!n.some(e=>e==null))return{schema_version:1,type:`terminal_output`,status:typeof t.status==`string`?t.status:`unknown`,is_error:t.is_error===!0,parts:n,truncated:t.truncated===!0,...typeof t.exit_code==`number`||t.exit_code===null?{exit_code:t.exit_code}:{},...typeof t.wall_time_seconds==`number`||t.wall_time_seconds===null?{wall_time_seconds:t.wall_time_seconds}:{}}}var le=new Set([`completed`,`failed`,`error`,`running`,`unknown`]),U=new Set([`failed`,`error`]);function ue(e){if(e)return{status:le.has(e.status)?e.status:`unknown`,exit_code:typeof e.exit_code==`number`?e.exit_code:null,wall_time_seconds:typeof e.wall_time_seconds==`number`?e.wall_time_seconds:null}}function de(e){if(!Array.isArray(e)||e.length===0)return;let t=[];for(let n of e){let e=V(n);if(!e)return;if(e.kind===`command`){if(typeof e.command!=`string`)return;t.push({kind:`command`,command:e.command,workdir:typeof e.workdir==`string`?e.workdir:null,metadata:V(e.metadata)??{}});continue}if(e.kind===`session`){if(e.scope!==`shell`&&e.scope!==`cell`||e.operation!==`write`&&e.operation!==`poll`)return;t.push({kind:`session`,scope:e.scope,operation:e.operation,ref:typeof e.ref==`string`?e.ref:null,chars:typeof e.chars==`string`?e.chars:null});continue}if(e.kind===`other`&&typeof e.name==`string`&&e.name!==``){t.push({kind:`other`,name:e.name});continue}return}return t}function fe(e){let t=de(e.invocations);if(!(!t||typeof e.complete!=`boolean`||typeof e.truncated!=`boolean`))return{schema_version:1,type:`program`,title:typeof e.title==`string`?e.title:null,complete:e.complete,invocations:t,truncated:e.truncated}}function pe(e){if(!(e.scope!==`shell`&&e.scope!==`cell`||e.operation!==`write`&&e.operation!==`poll`||typeof e.truncated!=`boolean`))return{schema_version:1,type:`session_ref`,scope:e.scope,operation:e.operation,ref:typeof e.ref==`string`?e.ref:null,chars:typeof e.chars==`string`?e.chars:null,truncated:e.truncated}}function me(e){if(typeof e.query==`string`)return{schema_version:1,type:`tool_search`,query:e.query,limit:typeof e.limit==`number`&&Number.isFinite(e.limit)?e.limit:null,...e.truncated===!0?{truncated:!0}:{}}}function he(e){let t=V(e),n=V(t?.sessions);if(!t||!n||typeof t.truncated!=`boolean`)return;let r=Object.create(null);for(let[e,t]of Object.entries(n)){let n=V(t);if(!n||!Number.isSafeInteger(n.ordinal)||n.opener_block_key!==null&&typeof n.opener_block_key!=`string`)return;r[e]={ordinal:n.ordinal,opener_block_key:n.opener_block_key}}return{sessions:r,truncated:t.truncated}}function ge(e){let t=V(e);if(t?.schema_version!==1||typeof t.name!=`string`||t.name===``||!(`input`in t)||typeof t.truncated!=`boolean`)return null;let n=t.span,r=Array.isArray(n)&&n.length===2&&Number.isSafeInteger(n[0])&&Number.isSafeInteger(n[1])&&n[0]>=0&&n[1]>=n[0]?[n[0],n[1]]:null;return{block:{kind:`external_call`,name:t.name,input:t.input,truncated:t.truncated},span:r}}function _e(e){let t=V(e);return!t||typeof t.status!=`string`||typeof t.truncated!=`boolean`||!(`value`in t)?null:{status:t.status,value:t.value,truncated:t.truncated}}function ve(e){if(e.source!==`update_plan`||typeof e.call_status!=`string`||!Array.isArray(e.items))return;let t=e.items.map(e=>{let t=V(e);return t&&typeof t.step==`string`&&typeof t.status==`string`?{step:t.step,status:t.status}:null}),n=e.result===void 0?void 0:_e(e.result);if(!(t.some(e=>e==null)||e.result!==void 0&&!n))return{schema_version:1,type:`plan`,source:`update_plan`,call_status:e.call_status,explanation:typeof e.explanation==`string`?e.explanation:null,items:t,...n?{result:n}:{}}}function ye(e){let t=V(e.completion);if(e.source!==`web_search_call`||typeof e.call_status!=`string`||typeof e.query!=`string`||!V(e.action)||!t||typeof t.status!=`string`||typeof t.query!=`string`||!V(t.action)||!Array.isArray(t.results))return;let n=t.results.map(e=>{let t=V(e);return!t||typeof t.title!=`string`||typeof t.url!=`string`?null:{title:t.title,url:t.url,...typeof t.domain==`string`?{domain:t.domain}:{},...typeof t.snippet==`string`?{snippet:t.snippet}:{},...typeof t.ref_id==`string`?{ref_id:t.ref_id}:{},...typeof t.type==`string`?{type:t.type}:{}}});if(!n.some(e=>e==null))return{schema_version:1,type:`web_search`,source:`web_search_call`,call_status:e.call_status,query:e.query,action:V(e.action),completion:{status:t.status,query:t.query,action:V(t.action),results:n,...typeof t.error==`string`?{error:t.error}:{},...typeof t.event_block_key==`string`?{event_block_key:t.event_block_key}:{}}}}function be(e){let t=V(e.completion),n=V(t?.duration);if(!(e.source!==`function_call`||typeof e.name!=`string`||typeof e.call_status!=`string`||!t||typeof t.status!=`string`||typeof t.server!=`string`||typeof t.tool!=`string`||!V(t.arguments)||!V(t.result)||!n||typeof n.secs!=`number`||!Number.isFinite(n.secs)||typeof n.nanos!=`number`||!Number.isFinite(n.nanos)))return{schema_version:1,type:`mcp`,source:`function_call`,name:e.name,call_status:e.call_status,completion:{status:t.status,server:t.server,tool:t.tool,arguments:V(t.arguments),result:V(t.result),duration:{secs:n.secs,nanos:n.nanos},...typeof t.event_block_key==`string`?{event_block_key:t.event_block_key}:{}}}}var xe=new Set([`spawn_agent`,`wait_agent`,`send_message`,`list_agents`,`followup_task`,`interrupt_agent`]);function Se(e){let t=typeof e.operation==`string`&&xe.has(e.operation)?e.operation:null,n=V(e.arguments),r=e.result===void 0?void 0:_e(e.result),i=e.child_conversation==null?null:V(e.child_conversation);if(!(!t||typeof e.call_status!=`string`||!n||e.result!==void 0&&!r||e.child_conversation!=null&&!i)&&!(i&&typeof i.conversation_key!=`string`))return{schema_version:1,type:`agent`,operation:t,call_status:e.call_status,arguments:n,...r?{result:r}:{},...i?{child_conversation:{conversation_key:i.conversation_key,...typeof i.role==`string`?{role:i.role}:{},...typeof i.nickname==`string`?{nickname:i.nickname}:{}}}:{}}}function W(e){let t=V(e.detail?.card);if(t?.schema_version!==1)return;if(t.type===`terminal`){if(!Array.isArray(t.commands)||t.commands.length===0)return;let n=t.commands.map(e=>{let t=V(e);return!t||typeof t.command!=`string`?null:{command:t.command,workdir:typeof t.workdir==`string`?t.workdir:null,metadata:V(t.metadata)??{}}});return n.some(e=>e==null)?void 0:{schema_version:1,type:`terminal`,status:typeof t.status==`string`?t.status:`unknown`,commands:n,output:H(e.output?.detail?.card),truncated:t.truncated===!0||e.output?.detail?.card!=null&&V(e.output.detail.card)?.truncated===!0}}if(t.type===`plan`)return ve(t);if(t.type===`web_search`)return ye(t);if(t.type===`mcp`)return be(t);if(t.type===`agent`)return Se(t);if(t.type===`program`)return fe(t);if(t.type===`session_ref`)return pe(t);if(t.type===`tool_search`)return me(t);if(t.type!==`patch`)return;let n=se(t.files);if(n==null)return;let r=V(t.completion),i=r?.schema_version===1&&r.type===`patch`?r:t,a=ce(i.files);if(a!=null)return{schema_version:1,type:`patch`,source:typeof t.source==`string`?t.source:`patch_apply_end`,status:typeof i.status==`string`?i.status:`unknown`,files:a,request_files:r?n:void 0,patch:typeof t.patch==`string`?t.patch:void 0,success:typeof i.success==`boolean`?i.success:null,stdout:typeof i.stdout==`string`?i.stdout:null,stderr:typeof i.stderr==`string`?i.stderr:null,has_diff:typeof i.has_diff==`boolean`?i.has_diff:a.some(e=>typeof e.unified_diff==`string`),truncated:t.truncated===!0||i.truncated===!0,event_payload_key:typeof i.event_block_key==`string`?i.event_block_key:void 0}}function Ce(e){let t=e[0],n=t.kind===`command`?t.command:t.kind===`session`?[w(t.operation),S(t.scope,t.ref)].filter(Boolean).join(` `):t.name;return e.length>1?`${n} +${e.length-1} more`:n}function we(e){return[S(e.scope,e.ref),e.chars==null?``:D(e.chars)].filter(Boolean).join(` · `)||e.operation}function G(e){if(e)return e.replace(/^\[((?:\$)[^\]\r\n]+)\]\([^\)\r\n]*\/SKILL\.md\)[ \t]*/,(e,t,n,r)=>n+e.length<r.length?`${t} `:t)}function Te(e,t){let n=[];for(let r of e){if(r.kind===`assistant`||r.kind===`user`||r.kind===`text`){let e=r.kind===`assistant`?ge(r.detail?.external_call):null,t=e?.span!=null&&r.text!=null&&e.span[1]<=r.text.length?e.span:null,i=t?`${r.text.slice(0,t[0])}${r.text.slice(t[1])}`.replace(/[ \t]*\n+$/,``):r.text;i&&n.push({kind:`text`,text:i,...r.block_key?{block_key:r.block_key}:{}}),e&&t&&n.push({...e.block,...r.block_key?{block_key:r.block_key}:{}});let a=ae(r.detail?.markers);a&&n.push({kind:`system_actions`,actions:a,...r.block_key?{payload_key:r.block_key}:{}});continue}if(r.kind===`thinking`){r.text?.trim()&&n.push({kind:`thinking`,text:r.text});continue}if(r.kind===`reasoning`){if(t===`codex`){let e=ie(r);e&&n.push(e)}else r.text?.trim()&&n.push({kind:`thinking`,text:r.text});continue}if(r.kind===`tool_call`){let e=r;if(t===`claude`&&r.detail==null&&typeof e.input_summary==`string`&&typeof e.preview==`string`&&`result`in e){n.push(e);continue}let i=typeof r.detail?.name==`string`?r.detail.name:null,a=typeof r.detail?.args==`string`?r.detail.args:``,o=W(r),s=o?.type===`terminal`?o:null,c=o?.type===`patch`?o:null,l=o?.type===`plan`?o:null,u=o?.type===`web_search`?o:null,d=o?.type===`mcp`?o:null,f=o?.type===`agent`?o:null,p=o?.type===`program`?o:null,m=o?.type===`session_ref`?o:null,h=o?.type===`tool_search`?o:null,g=s?{command:s.commands[0].command,workdir:s.commands[0].workdir}:u?{query:u.query,action:u.action}:d?d.completion.arguments:f?f.arguments:z(a),_=t===`codex`?ue(H(r.output?.detail?.card)):void 0,v=s?.output?.is_error===!0||c?.success===!1||U.has(u?.completion.status??``)||U.has(d?.completion.status??``)||U.has(_?.status??``),y=B(l?.explanation)??B(u?.query)??(d?B(`${d.completion.tool} · ${d.completion.server}`):void 0)??(f?B(f.operation):void 0)??B(h?.query)??B(p?.title)??(p?B(Ce(p.invocations)):void 0)??(m?B(we(m)):void 0),b=l?.result?.value??u?.completion.error??d?.completion.result??f?.result?.value??null,x=typeof b==`string`?b:b==null?null:JSON.stringify(b,null,2);n.push({kind:`tool_call`,name:i,input_summary:s?JSON.stringify({commands:s.commands}):a||r.text||``,input:g,preview:s?.commands[0].command??c?.files.map(e=>e.move_path??e.path).filter(Boolean).join(`, `)??y??(r.text??a).split(`
|
|
1
|
+
import{Ft as e,Rt as t,_t as n,ft as r,ht as i}from"./useKeymap-CW7Up0Ay.js";import{Ft as a}from"./index-CYZ3NLqF.js";var o=t(e(),1),s=class extends Error{status;constructor(e){super(`HTTP ${e}`),this.status=e,this.name=`HttpError`}};function c(e){return e?.name===`AbortError`}async function l(e,t){let n=await fetch(e,t?{signal:t}:void 0);if(!n.ok)throw new s(n.status);return await n.json()}function u(e){let t=e?.data_version;return typeof t==`string`&&t!==``?t:e?.generated_at??``}var d={legacy_bridge_pending:{reason:`legacy_bridge_pending`,message:`Transcripts have not finished moving into the conversation store. Run cctally cache-sync to finish the import.`,retryable:!1},maintenance:{reason:`maintenance`,message:`The conversation store is busy with maintenance. Conversations return once it finishes.`,retryable:!0},schema_behind:{reason:`schema_behind`,message:`The conversation store is behind this version of cctally. Run cctally cache-sync to bring it up to date.`,retryable:!1},schema_ahead:{reason:`schema_ahead`,message:`The conversation store was written by a newer version of cctally. Update cctally to read it.`,retryable:!1}},f={reason:`unavailable`,message:`The conversation store is not available right now.`,retryable:!0};function p(e){if(typeof e!=`object`||!e)return null;let t=e;return t.status===`degraded`?typeof t.degraded_reason==`string`&&t.degraded_reason?t.degraded_reason:f.reason:null}function m(e){return d[e]??{...f,reason:e||f.reason}}function h(e,t,n){n!==void 0&&e.append(t,String(n))}function g(e,t={}){let n=new URLSearchParams;return n.append(`source`,e),h(n,`account`,t.accountKey),h(n,`project_key`,t.projectKey),h(n,`model`,t.model),h(n,`limit`,t.limit),h(n,`cursor`,t.cursor),h(n,`selected`,t.selected),`/api/conversations?${n.toString()}`}function _(e,t){let n=new URLSearchParams({source:e});return h(n,`account`,t),`/api/conversations/facets?${n.toString()}`}function v(e,t){let n=new URLSearchParams;return n.append(`source`,e),h(n,`account`,t.accountKey),n.append(`q`,t.query),h(n,`kind`,t.kind),h(n,`limit`,t.limit),h(n,`cursor`,t.cursor),`/api/conversation/search?${n.toString().replace(/\+/g,`%20`)}`}var y={detail:``,outline:`/outline`,find:`/find`,prompts:`/prompts`,payload:`/payload`,export:`/export`,"anon-map":`/anon-map`,events:`/events`,media:`/media`};function b(e,t,r){let i=n(e);if(i.source===`codex`&&!i.key.startsWith(`v1.`))throw Error(`Codex conversation keys must be qualified`);let a=new URLSearchParams;h(a,`account`,i.account_key);for(let[e,t]of Object.entries(r??{}))t!==void 0&&a.append(e,typeof t==`boolean`?t?`1`:`0`:String(t));let o=a.size?`?${a.toString().replace(/\+/g,`%20`)}`:``;return`/api/conversation/${encodeURIComponent(i.key)}${y[t]}${o}`}function x(e){let t=e.native_card;return t?.type===`session_ref`?t.scope===`shell`&&t.ref!=null?[t.ref]:[]:t?.type===`program`?t.invocations.flatMap(e=>e.kind===`session`&&e.scope===`shell`&&e.ref!=null?[e.ref]:[]):[]}function S(e,t){return t==null?``:e===`shell`?`session ${t}`:`cell ${t}`}function C(e,t){return t==null?``:e===`shell`?`s${t}`:`c${t}`}function w(e){return e===`write`?`wrote to`:`polled`}function T(e){return e===`write`?`wrote`:`poll`}var E=60;function D(e){let t=e.replace(/\s+/g,` `).trim();return t.length>E?`${t.slice(0,E)}…`:t}function O(e){let t=new Set(e.flatMap(e=>x(e)));return t.size===1?[...t][0]:null}function k(e,t,n,r){if(!e||t!==`shell`||n==null)return`silent`;let i=e.sessions[n];return i?.opener_block_key==null?e.truncated?`index_truncated`:`not_retained`:r!=null&&r===i.opener_block_key?`opener`:`silent`}function A(e){return new Set(e.map(e=>e.parent_uuid))}function j(e){let t=new Map;for(let n of e){let e=t.get(n.parent_uuid);e?e.push(n):t.set(n.parent_uuid,[n])}return t}function M(e){return e.kind===`reasoning`?e.landmark_key:e.block_key}var N={tool_error:`error`,plan:`plan`,reasoning:`heading`};function P(e,t){if(!t?.length)return[];let n=j(t),r=[];return e.forEach((e,t)=>{for(let i of n.get(e.uuid)??[])r.push({landmark:i,ownerTurnIndex:t})}),r}var F=class extends Error{constructor(){super(`Conversation indexing is still finishing.`)}},I=class extends Error{reason;constructor(e){let t=m(e);super(t.message),this.name=`ConversationDegraded`,this.reason=t.reason}};function L(e){return typeof e==`number`&&Number.isFinite(e)?e:0}function ee(e){return typeof e==`number`&&Number.isFinite(e)?e:null}function R(e){if(e)return e.source===`codex`||`cached_input`in e||`reasoning_output`in e?{source:`codex`,input:L(e.input),output:L(e.output),cache_creation:0,cache_read:0,cached_input:L(e.cached_input),reasoning_output:L(e.reasoning_output)}:{source:`claude`,input:L(e.input),output:L(e.output),cache_creation:L(e.cache_creation??e.cache_create),cache_read:L(e.cache_read)}}function te(e){let t=2166136261;for(let n=0;n<e.length;n++)t^=e.charCodeAt(n),t=Math.imul(t,16777619);return t>>>0||1}function z(e){if(typeof e!=`string`||e.trim()===``)return null;try{let t=JSON.parse(e);return t&&typeof t==`object`&&!Array.isArray(t)?t:{value:t}}catch{return{raw:e}}}var ne=new Set([`create_branch`,`stage`,`commit`,`push`,`create_pr`]);function B(e){return typeof e==`string`&&e.trim()!==``?e.trim():void 0}function re(e){if(!Array.isArray(e)||e.length===0)return;let t=[];for(let n of e){let e=V(n);if(!e||typeof e.key!=`string`||typeof e.text!=`string`)return;t.push({key:e.key,text:e.text})}return t}function ie(e){let t=V(e.detail?.reasoning);if(t?.schema_version===1){let n=B(t.title),r=B(t.summary),i=B(t.body);if(!n&&!r&&!i)return null;let a=re(t.headings);return{kind:`codex_reasoning`,source:B(t.source)??`codex`,title:n,summary:r,body:i,...a?{headings:a}:{},...e.block_key?{block_key:e.block_key}:{}}}let n=B(e.text);return n?{kind:`codex_reasoning`,source:`codex`,body:n,...e.block_key?{block_key:e.block_key}:{}}:null}function ae(e){if(!Array.isArray(e)||e.length===0)return null;let t=[];for(let n of e){let e=V(n);if(!e||e.schema_version!==1)return null;if(e.type===`git`&&typeof e.action==`string`&&ne.has(e.action)){t.push({type:`git`,action:e.action,...e.action===`create_pr`&&typeof e.draft==`boolean`?{draft:e.draft}:{}});continue}if(e.type===`memory_citation`&&Number.isSafeInteger(e.citation_count)&&Number(e.citation_count)>=0&&Number.isSafeInteger(e.rollout_count)&&Number(e.rollout_count)>=0){t.push({type:`memory_citation`,citation_count:Number(e.citation_count),rollout_count:Number(e.rollout_count)});continue}return null}return t}function oe(e){let t=V(e.detail?.lifecycle);return t?.schema_version!==1||t.event!==`task_started`&&t.event!==`task_complete`?null:{kind:`codex_lifecycle`,event:t.event,...B(t.message)?{message:B(t.message)}:{},...B(t.error)?{error:B(t.error)}:{},...typeof t.duration_ms==`number`&&Number.isFinite(t.duration_ms)?{duration_ms:t.duration_ms}:{},...e.block_key?{payload_key:e.block_key}:{}}}function V(e){return typeof e==`object`&&e&&!Array.isArray(e)?e:null}function se(e){if(!Array.isArray(e))return null;let t=[];for(let n of e){let e=V(n);if(!e)return null;let r={};for(let t of[`path`,`move_path`,`status`])typeof e[t]==`string`&&(r[t]=e[t]);t.push(r)}return t}function ce(e){if(!Array.isArray(e))return null;let t=[];for(let n of e){let e=V(n);if(!e)return null;let r={};for(let t of[`path`,`move_path`,`status`,`unified_diff`,`raw`,`raw_extra`])typeof e[t]==`string`&&(r[t]=e[t]);typeof e.truncated==`boolean`&&(r.truncated=e.truncated),(e.diff_source===`retained`||e.diff_source===`derived`)&&(r.diff_source=e.diff_source),t.push(r)}return t}function H(e){let t=V(e);if(t?.schema_version!==1||t.type!==`terminal_output`||!Array.isArray(t.parts))return;let n=t.parts.map(e=>{let t=V(e);if(!t||t.type!==`text`&&t.type!==`raw`||typeof t.text!=`string`)return null;let n=t.stream===`stdout`||t.stream===`stderr`?t.stream:`output`;return{type:t.type,stream:n,text:t.text}});if(!n.some(e=>e==null))return{schema_version:1,type:`terminal_output`,status:typeof t.status==`string`?t.status:`unknown`,is_error:t.is_error===!0,parts:n,truncated:t.truncated===!0,...typeof t.exit_code==`number`||t.exit_code===null?{exit_code:t.exit_code}:{},...typeof t.wall_time_seconds==`number`||t.wall_time_seconds===null?{wall_time_seconds:t.wall_time_seconds}:{}}}var le=new Set([`completed`,`failed`,`error`,`running`,`unknown`]),U=new Set([`failed`,`error`]);function ue(e){if(e)return{status:le.has(e.status)?e.status:`unknown`,exit_code:typeof e.exit_code==`number`?e.exit_code:null,wall_time_seconds:typeof e.wall_time_seconds==`number`?e.wall_time_seconds:null}}function de(e){if(!Array.isArray(e)||e.length===0)return;let t=[];for(let n of e){let e=V(n);if(!e)return;if(e.kind===`command`){if(typeof e.command!=`string`)return;t.push({kind:`command`,command:e.command,workdir:typeof e.workdir==`string`?e.workdir:null,metadata:V(e.metadata)??{}});continue}if(e.kind===`session`){if(e.scope!==`shell`&&e.scope!==`cell`||e.operation!==`write`&&e.operation!==`poll`)return;t.push({kind:`session`,scope:e.scope,operation:e.operation,ref:typeof e.ref==`string`?e.ref:null,chars:typeof e.chars==`string`?e.chars:null});continue}if(e.kind===`other`&&typeof e.name==`string`&&e.name!==``){t.push({kind:`other`,name:e.name});continue}return}return t}function fe(e){let t=de(e.invocations);if(!(!t||typeof e.complete!=`boolean`||typeof e.truncated!=`boolean`))return{schema_version:1,type:`program`,title:typeof e.title==`string`?e.title:null,complete:e.complete,invocations:t,truncated:e.truncated}}function pe(e){if(!(e.scope!==`shell`&&e.scope!==`cell`||e.operation!==`write`&&e.operation!==`poll`||typeof e.truncated!=`boolean`))return{schema_version:1,type:`session_ref`,scope:e.scope,operation:e.operation,ref:typeof e.ref==`string`?e.ref:null,chars:typeof e.chars==`string`?e.chars:null,truncated:e.truncated}}function me(e){if(typeof e.query==`string`)return{schema_version:1,type:`tool_search`,query:e.query,limit:typeof e.limit==`number`&&Number.isFinite(e.limit)?e.limit:null,...e.truncated===!0?{truncated:!0}:{}}}function he(e){let t=V(e),n=V(t?.sessions);if(!t||!n||typeof t.truncated!=`boolean`)return;let r=Object.create(null);for(let[e,t]of Object.entries(n)){let n=V(t);if(!n||!Number.isSafeInteger(n.ordinal)||n.opener_block_key!==null&&typeof n.opener_block_key!=`string`)return;r[e]={ordinal:n.ordinal,opener_block_key:n.opener_block_key}}return{sessions:r,truncated:t.truncated}}function ge(e){let t=V(e);if(t?.schema_version!==1||typeof t.name!=`string`||t.name===``||!(`input`in t)||typeof t.truncated!=`boolean`)return null;let n=t.span,r=Array.isArray(n)&&n.length===2&&Number.isSafeInteger(n[0])&&Number.isSafeInteger(n[1])&&n[0]>=0&&n[1]>=n[0]?[n[0],n[1]]:null;return{block:{kind:`external_call`,name:t.name,input:t.input,truncated:t.truncated},span:r}}function _e(e){let t=V(e);return!t||typeof t.status!=`string`||typeof t.truncated!=`boolean`||!(`value`in t)?null:{status:t.status,value:t.value,truncated:t.truncated}}function ve(e){if(e.source!==`update_plan`||typeof e.call_status!=`string`||!Array.isArray(e.items))return;let t=e.items.map(e=>{let t=V(e);return t&&typeof t.step==`string`&&typeof t.status==`string`?{step:t.step,status:t.status}:null}),n=e.result===void 0?void 0:_e(e.result);if(!(t.some(e=>e==null)||e.result!==void 0&&!n))return{schema_version:1,type:`plan`,source:`update_plan`,call_status:e.call_status,explanation:typeof e.explanation==`string`?e.explanation:null,items:t,...n?{result:n}:{}}}function ye(e){let t=V(e.completion);if(e.source!==`web_search_call`||typeof e.call_status!=`string`||typeof e.query!=`string`||!V(e.action)||!t||typeof t.status!=`string`||typeof t.query!=`string`||!V(t.action)||!Array.isArray(t.results))return;let n=t.results.map(e=>{let t=V(e);return!t||typeof t.title!=`string`||typeof t.url!=`string`?null:{title:t.title,url:t.url,...typeof t.domain==`string`?{domain:t.domain}:{},...typeof t.snippet==`string`?{snippet:t.snippet}:{},...typeof t.ref_id==`string`?{ref_id:t.ref_id}:{},...typeof t.type==`string`?{type:t.type}:{}}});if(!n.some(e=>e==null))return{schema_version:1,type:`web_search`,source:`web_search_call`,call_status:e.call_status,query:e.query,action:V(e.action),completion:{status:t.status,query:t.query,action:V(t.action),results:n,...typeof t.error==`string`?{error:t.error}:{},...typeof t.event_block_key==`string`?{event_block_key:t.event_block_key}:{}}}}function be(e){let t=V(e.completion),n=V(t?.duration);if(!(e.source!==`function_call`||typeof e.name!=`string`||typeof e.call_status!=`string`||!t||typeof t.status!=`string`||typeof t.server!=`string`||typeof t.tool!=`string`||!V(t.arguments)||!V(t.result)||!n||typeof n.secs!=`number`||!Number.isFinite(n.secs)||typeof n.nanos!=`number`||!Number.isFinite(n.nanos)))return{schema_version:1,type:`mcp`,source:`function_call`,name:e.name,call_status:e.call_status,completion:{status:t.status,server:t.server,tool:t.tool,arguments:V(t.arguments),result:V(t.result),duration:{secs:n.secs,nanos:n.nanos},...typeof t.event_block_key==`string`?{event_block_key:t.event_block_key}:{}}}}var xe=new Set([`spawn_agent`,`wait_agent`,`send_message`,`list_agents`,`followup_task`,`interrupt_agent`]);function Se(e){let t=typeof e.operation==`string`&&xe.has(e.operation)?e.operation:null,n=V(e.arguments),r=e.result===void 0?void 0:_e(e.result),i=e.child_conversation==null?null:V(e.child_conversation);if(!(!t||typeof e.call_status!=`string`||!n||e.result!==void 0&&!r||e.child_conversation!=null&&!i)&&!(i&&typeof i.conversation_key!=`string`))return{schema_version:1,type:`agent`,operation:t,call_status:e.call_status,arguments:n,...r?{result:r}:{},...i?{child_conversation:{conversation_key:i.conversation_key,...typeof i.role==`string`?{role:i.role}:{},...typeof i.nickname==`string`?{nickname:i.nickname}:{}}}:{}}}function W(e){let t=V(e.detail?.card);if(t?.schema_version!==1)return;if(t.type===`terminal`){if(!Array.isArray(t.commands)||t.commands.length===0)return;let n=t.commands.map(e=>{let t=V(e);return!t||typeof t.command!=`string`?null:{command:t.command,workdir:typeof t.workdir==`string`?t.workdir:null,metadata:V(t.metadata)??{}}});return n.some(e=>e==null)?void 0:{schema_version:1,type:`terminal`,status:typeof t.status==`string`?t.status:`unknown`,commands:n,output:H(e.output?.detail?.card),truncated:t.truncated===!0||e.output?.detail?.card!=null&&V(e.output.detail.card)?.truncated===!0}}if(t.type===`plan`)return ve(t);if(t.type===`web_search`)return ye(t);if(t.type===`mcp`)return be(t);if(t.type===`agent`)return Se(t);if(t.type===`program`)return fe(t);if(t.type===`session_ref`)return pe(t);if(t.type===`tool_search`)return me(t);if(t.type!==`patch`)return;let n=se(t.files);if(n==null)return;let r=V(t.completion),i=r?.schema_version===1&&r.type===`patch`?r:t,a=ce(i.files);if(a!=null)return{schema_version:1,type:`patch`,source:typeof t.source==`string`?t.source:`patch_apply_end`,status:typeof i.status==`string`?i.status:`unknown`,files:a,request_files:r?n:void 0,patch:typeof t.patch==`string`?t.patch:void 0,success:typeof i.success==`boolean`?i.success:null,stdout:typeof i.stdout==`string`?i.stdout:null,stderr:typeof i.stderr==`string`?i.stderr:null,has_diff:typeof i.has_diff==`boolean`?i.has_diff:a.some(e=>typeof e.unified_diff==`string`),truncated:t.truncated===!0||i.truncated===!0,event_payload_key:typeof i.event_block_key==`string`?i.event_block_key:void 0}}function Ce(e){let t=e[0],n=t.kind===`command`?t.command:t.kind===`session`?[w(t.operation),S(t.scope,t.ref)].filter(Boolean).join(` `):t.name;return e.length>1?`${n} +${e.length-1} more`:n}function we(e){return[S(e.scope,e.ref),e.chars==null?``:D(e.chars)].filter(Boolean).join(` · `)||e.operation}function G(e){if(e)return e.replace(/^\[((?:\$)[^\]\r\n]+)\]\([^\)\r\n]*\/SKILL\.md\)[ \t]*/,(e,t,n,r)=>n+e.length<r.length?`${t} `:t)}function Te(e,t){let n=[];for(let r of e){if(r.kind===`assistant`||r.kind===`user`||r.kind===`text`){let e=r.kind===`assistant`?ge(r.detail?.external_call):null,t=e?.span!=null&&r.text!=null&&e.span[1]<=r.text.length?e.span:null,i=t?`${r.text.slice(0,t[0])}${r.text.slice(t[1])}`.replace(/[ \t]*\n+$/,``):r.text;i&&n.push({kind:`text`,text:i,...r.block_key?{block_key:r.block_key}:{}}),e&&t&&n.push({...e.block,...r.block_key?{block_key:r.block_key}:{}});let a=ae(r.detail?.markers);a&&n.push({kind:`system_actions`,actions:a,...r.block_key?{payload_key:r.block_key}:{}});continue}if(r.kind===`thinking`){r.text?.trim()&&n.push({kind:`thinking`,text:r.text});continue}if(r.kind===`reasoning`){if(t===`codex`){let e=ie(r);e&&n.push(e)}else r.text?.trim()&&n.push({kind:`thinking`,text:r.text});continue}if(r.kind===`tool_call`){let e=r;if(t===`claude`&&r.detail==null&&typeof e.input_summary==`string`&&typeof e.preview==`string`&&`result`in e){n.push(e);continue}let i=typeof r.detail?.name==`string`?r.detail.name:null,a=typeof r.detail?.args==`string`?r.detail.args:``,o=W(r),s=o?.type===`terminal`?o:null,c=o?.type===`patch`?o:null,l=o?.type===`plan`?o:null,u=o?.type===`web_search`?o:null,d=o?.type===`mcp`?o:null,f=o?.type===`agent`?o:null,p=o?.type===`program`?o:null,m=o?.type===`session_ref`?o:null,h=o?.type===`tool_search`?o:null,g=s?{command:s.commands[0].command,workdir:s.commands[0].workdir}:u?{query:u.query,action:u.action}:d?d.completion.arguments:f?f.arguments:z(a),_=t===`codex`?ue(H(r.output?.detail?.card)):void 0,v=s?.output?.is_error===!0||c?.success===!1||U.has(u?.completion.status??``)||U.has(d?.completion.status??``)||U.has(_?.status??``),y=B(l?.explanation)??B(u?.query)??(d?B(`${d.completion.tool} · ${d.completion.server}`):void 0)??(f?B(f.operation):void 0)??B(h?.query)??B(p?.title)??(p?B(Ce(p.invocations)):void 0)??(m?B(we(m)):void 0),b=l?.result?.value??u?.completion.error??d?.completion.result??f?.result?.value??null,x=typeof b==`string`?b:b==null?null:JSON.stringify(b,null,2);n.push({kind:`tool_call`,name:i,input_summary:s?JSON.stringify({commands:s.commands}):a||r.text||``,input:g,preview:s?.commands[0].command??c?.files.map(e=>e.move_path??e.path).filter(Boolean).join(`, `)??y??(r.text??a).split(`
|
|
2
2
|
`)[0]??``,tool_use_id:r.block_key??null,...r.block_key?{block_key:r.block_key}:{},payload_capable:r.block_key!=null,payload_kind:`call`,native_card:o,..._?{outcome:_}:{},web_search:u?{query:u.query,links:u.completion.results}:void 0,result:r.output||x!=null?{text:x??r.output?.text??``,truncated:s?.output?.truncated===!0||c?.truncated===!0||l?.result?.truncated===!0||f?.result?.truncated===!0,is_error:v}:null});continue}if(r.kind===`event`){let e=W(r);if(e?.type===`patch`){let t=[e.stdout,e.stderr].filter(e=>typeof e==`string`).join(``);n.push({kind:`tool_call`,name:`patch_apply_end`,input_summary:r.text??``,input:null,preview:e.files.map(e=>e.move_path??e.path).filter(Boolean).join(`, `)||`patch summary`,tool_use_id:r.block_key??null,...r.block_key?{block_key:r.block_key}:{},payload_capable:r.block_key!=null,payload_kind:`event`,native_card:e,result:{text:t,truncated:e.truncated===!0,is_error:e.success===!1||U.has(e.status)}});continue}let t=oe(r);if(t){n.push(t);continue}}if(r.kind===`tool_output`||r.kind===`tool_result`){let e=H(r.detail?.card);n.push({kind:`tool_result`,text:r.text??``,truncated:e?.truncated===!0,is_error:r.detail?.is_error===!0||e?.is_error===!0||U.has(e?.status??``),tool_use_id:r.call_id??r.block_key??null,...r.block_key?{block_key:r.block_key}:{}});continue}r.text?n.push({kind:`text`,text:r.text,...r.block_key?{block_key:r.block_key}:{}}):r.block_key&&n.push({kind:`text`,text:``,block_key:r.block_key})}return n}function Ee(e){let t=e.blocks.find(e=>e.kind===`event`),n=V(t?.detail?.lifecycle);return n?.event===`task_started`||n?.event===`task_complete`?`codex_${n.event}`:typeof t?.detail?.event==`string`?t.detail.event:t?.text?.split(`
|
|
3
3
|
`)[0]?.trim()||null}function De(e){let t=V(e);if(t?.schema_version!==1||typeof t.state!=`string`||!Array.isArray(t.events))return;let n=t.events.map(e=>{let t=V(e);return t&&typeof t.event==`string`&&t.payload_which===`event`&&typeof t.block_key==`string`?{event:t.event,payload_which:`event`,block_key:t.block_key}:null});if(!n.some(e=>e==null))return{schema_version:1,state:t.state,...V(t.started)?{started:V(t.started)}:{},...V(t.completed)?{completed:V(t.completed)}:{},events:n}}function Oe(e){let t=e.blocks.find(e=>e.kind===`meta`)?.detail,n=e.meta_kind??t?.meta_kind,r=e.meta_label??t?.meta_label,i=typeof r==`string`?r:Ee(e);return{meta_kind:n===`skill`||n===`command`||n===`context`||n===`compaction`||n===`notification`?n:i===`context_compacted`?`compaction`:e.kind===`event`?`notification`:`context`,meta_label:i,meta_sections:Array.isArray(e.meta_sections)?e.meta_sections.filter(e=>typeof e==`string`):void 0,skill_name:typeof e.skill_name==`string`?e.skill_name:null}}function ke(e,t){let n={session_id:e.key,uuid:t.item_key,id:te(t.item_key)},r=Te(t.blocks,e.source),i=t.blocks.filter(e=>e.kind===`user`||e.kind===`assistant`||e.kind===`text`).map(e=>e.text??``).filter(Boolean).join(`
|
|
4
4
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg" />
|
|
7
7
|
<title>cctally dashboard</title>
|
|
8
|
-
<script type="module" crossorigin src="/static/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/static/assets/index-CYZ3NLqF.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/static/assets/useKeymap-CW7Up0Ay.js">
|
|
10
10
|
<link rel="stylesheet" crossorigin href="/static/assets/index-BKITk1CT.css">
|
|
11
11
|
</head>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cctally",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.116.0",
|
|
4
4
|
"description": "Claude Code usage tracker and local dashboard for Pro/Max subscription limits - weekly cost-per-percent trend, quota forecasts, threshold alerts. ccusage-compatible.",
|
|
5
5
|
"homepage": "https://github.com/omrikais/cctally",
|
|
6
6
|
"repository": {
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"bin/_cctally_journal_repair.py",
|
|
44
44
|
"bin/_cctally_milestone_history.py",
|
|
45
45
|
"bin/_cctally_milestones.py",
|
|
46
|
+
"bin/_cctally_oauth_samples.py",
|
|
46
47
|
"bin/_cctally_parser.py",
|
|
47
48
|
"bin/_cctally_percent_breakdown.py",
|
|
48
49
|
"bin/_cctally_pricing_check.py",
|
|
@@ -67,7 +68,6 @@
|
|
|
67
68
|
"bin/_cctally_tui.py",
|
|
68
69
|
"bin/_cctally_update.py",
|
|
69
70
|
"bin/_cctally_weekrefs.py",
|
|
70
|
-
"bin/_lib_merge_gate.py",
|
|
71
71
|
"bin/_lib_quarantine.py",
|
|
72
72
|
"bin/_lib_account_binding.py",
|
|
73
73
|
"bin/_lib_account_protocol.py",
|
|
@@ -137,11 +137,13 @@
|
|
|
137
137
|
"bin/_lib_log.py",
|
|
138
138
|
"bin/_lib_meter_rate_change.py",
|
|
139
139
|
"bin/_lib_milestone_history.py",
|
|
140
|
+
"bin/_lib_oauth_samples.py",
|
|
140
141
|
"bin/_lib_outcome_quarantine.py",
|
|
141
142
|
"bin/_lib_perf.py",
|
|
142
143
|
"bin/_lib_pricing.py",
|
|
143
144
|
"bin/_lib_pricing_check.py",
|
|
144
145
|
"bin/_lib_pricing_debug.py",
|
|
146
|
+
"bin/_lib_provider_activity.py",
|
|
145
147
|
"bin/_lib_quota.py",
|
|
146
148
|
"bin/_lib_quota_alert_axes.py",
|
|
147
149
|
"bin/_lib_quota_calibration.py",
|
|
@@ -150,6 +152,7 @@
|
|
|
150
152
|
"bin/_lib_quota_model.py",
|
|
151
153
|
"bin/_lib_rate_change_delivery.py",
|
|
152
154
|
"bin/_lib_readme_refresh.py",
|
|
155
|
+
"bin/_lib_rebuild_progress.py",
|
|
153
156
|
"bin/_lib_reclaim_planner.py",
|
|
154
157
|
"bin/_lib_record.py",
|
|
155
158
|
"bin/_lib_rederive.py",
|
|
@@ -165,6 +168,7 @@
|
|
|
165
168
|
"bin/_lib_source_identity.py",
|
|
166
169
|
"bin/_lib_source_retry.py",
|
|
167
170
|
"bin/_lib_sqlite_close.py",
|
|
171
|
+
"bin/_lib_stale_proof.py",
|
|
168
172
|
"bin/_lib_stats_damage.py",
|
|
169
173
|
"bin/_lib_stats_publish.py",
|
|
170
174
|
"bin/_lib_stats_wal.py",
|
|
@@ -175,6 +179,7 @@
|
|
|
175
179
|
"bin/_lib_transcript_access.py",
|
|
176
180
|
"bin/_lib_view_models.py",
|
|
177
181
|
"bin/_lib_wal_checkpoint.py",
|
|
182
|
+
"bin/_lib_worker_launches.py",
|
|
178
183
|
"bin/_lib_write_budget.py",
|
|
179
184
|
"bin/_lib_write_io.py",
|
|
180
185
|
"bin/cctally",
|
package/bin/_lib_merge_gate.py
DELETED
|
@@ -1,452 +0,0 @@
|
|
|
1
|
-
"""Conservative impact selection for merge certification (stdlib only).
|
|
2
|
-
|
|
3
|
-
This is a reviewed component policy, not proof of every possible dependency.
|
|
4
|
-
Unknown paths and shared/infrastructure changes require the full estate. The
|
|
5
|
-
scheduled full run and the release run remain the cross-component backstop.
|
|
6
|
-
"""
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
import argparse
|
|
10
|
-
import hashlib
|
|
11
|
-
import importlib.util
|
|
12
|
-
import json
|
|
13
|
-
import os
|
|
14
|
-
from pathlib import Path, PurePosixPath
|
|
15
|
-
import signal
|
|
16
|
-
import subprocess
|
|
17
|
-
import sys
|
|
18
|
-
|
|
19
|
-
GATE_ID = 'cctally-test-remote/merge-focused@1'
|
|
20
|
-
MAX_SECONDS = 300
|
|
21
|
-
# All of these are leaf presentation components. Their entire frontend estate
|
|
22
|
-
# runs, including their consumers, instead of relying on a TS import heuristic.
|
|
23
|
-
PRESENTATION_FILES = frozenset(
|
|
24
|
-
'dashboard/web/src/components/' + name + '.tsx'
|
|
25
|
-
for name in ('ZoneTag', 'ModelLegend', 'SortableHeader', 'HelpOverlay',
|
|
26
|
-
'AlertsEmptyGauge', 'SessionsControls', 'BasketChip', 'Toast')
|
|
27
|
-
)
|
|
28
|
-
SMOKE_FILES = ('tests/test_cli_smoke.py', 'tests/test_lib_json_envelope.py')
|
|
29
|
-
PRESENTATION_PYTEST = ('tests/test_dashboard_handler_static.py',)
|
|
30
|
-
# The reviewed memory publication set: both topic stores and the topic metadata.
|
|
31
|
-
# A private test pins it to the publication engine's own definition. Its
|
|
32
|
-
# configuration is NOT memory, so a change to it is ordinary task work.
|
|
33
|
-
MEMORY_PUBLICATION_SET = ('.claude-memory/**', '.agentmem/codex-memory/**', '.agentmem/topics.json')
|
|
34
|
-
MEMORY_CONFIGURATION = '.agentmem/config.json'
|
|
35
|
-
# Every test module that reads the memory corpus, beside the smoke files and
|
|
36
|
-
# the Doc lint harness: together they certify a memory-only candidate.
|
|
37
|
-
MEMORY_PYTEST = ('tests/test_cctally_memory.py', 'tests/test_agent_workflows.py',
|
|
38
|
-
'tests/test_session_workflow_texts.py')
|
|
39
|
-
# The capture publishes regular files only (a link is refused), so a memory
|
|
40
|
-
# path that is anything else on either side is not a memory publication.
|
|
41
|
-
REGULAR_MODES = ('100644', '100755')
|
|
42
|
-
# The instruction-text class (#894): agent-instruction prose whose every reader
|
|
43
|
-
# is one of INSTRUCTIONS_PYTEST. Markdown at any depth under these trees,
|
|
44
|
-
# nested CLAUDE.md/AGENTS.md included.
|
|
45
|
-
INSTRUCTION_TREES = ('.agent-workflows/skills/', '.claude/skills/', '.agents/skills/',
|
|
46
|
-
'.agent-workflows/contracts/', 'docs/superpowers/')
|
|
47
|
-
INSTRUCTION_NAMES = ('CLAUDE.md', 'AGENTS.md')
|
|
48
|
-
# Every nested instruction file outside the trees. A new one is a structural
|
|
49
|
-
# change to the instruction chain: its readers depend on where it lands, so it
|
|
50
|
-
# selects the full estate until a reviewed policy change lists it here.
|
|
51
|
-
NESTED_INSTRUCTION_FILES = ('bin/AGENTS.md', 'dashboard/AGENTS.md')
|
|
52
|
-
# The generator inputs of the root AGENTS.md (its configuration is not one).
|
|
53
|
-
INSTRUCTION_INPUTS = ('.agentmem/codex.md', '.agentmem/manifest.json')
|
|
54
|
-
# Every test module that reads, validates or scans an instruction path,
|
|
55
|
-
# beside the smoke files and the Doc lint harness.
|
|
56
|
-
INSTRUCTIONS_PYTEST = ('tests/test_agent_workflows.py', 'tests/test_session_workflow_texts.py',
|
|
57
|
-
'tests/test_cctally_memory.py', 'tests/test_session_issues.py',
|
|
58
|
-
'tests/test_session_provenance.py', 'tests/test_linux_matrix_gate.py',
|
|
59
|
-
'tests/test_release_internals.py', 'tests/test_quota_budget_error_harness.py',
|
|
60
|
-
'tests/test_session_policy.py', 'tests/test_lib_share.py',
|
|
61
|
-
'tests/test_dashboard_source_kernel.py', 'tests/test_share_privacy_detector.py',
|
|
62
|
-
'tests/test_fixture_cache.py')
|
|
63
|
-
# An instruction path is eligible only as a non-executable regular file.
|
|
64
|
-
INSTRUCTION_MODES = ('100644',)
|
|
65
|
-
# The two session execution plans are documentation: their only readers are
|
|
66
|
-
# people and the Doc lint harness, so a plan refresh takes the documentation
|
|
67
|
-
# focus. Exactly these two paths; any other docs/ Markdown is unclassified.
|
|
68
|
-
EXECUTION_PLAN_PATHS = ('docs/cctally-claude-execution-plan.md', 'docs/cctally-execution-plan.md')
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def _git(repo, *args):
|
|
72
|
-
proc = subprocess.run(['git', '--no-optional-locks', '-C', str(repo), *args],
|
|
73
|
-
capture_output=True)
|
|
74
|
-
if proc.returncode:
|
|
75
|
-
raise ValueError('git revision/diff failed: ' + proc.stderr.decode(errors='replace').strip())
|
|
76
|
-
return proc.stdout
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
def _changed_names(data):
|
|
80
|
-
"""--name-only -z lists both endpoints when rename detection is disabled."""
|
|
81
|
-
return [p.decode('utf-8', errors='strict') for p in data.split(b'\0') if p]
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def basis(repo, base_rev, head='HEAD', *, working=True):
|
|
85
|
-
if not base_rev or base_rev.startswith('-'):
|
|
86
|
-
raise ValueError('base revision must be nonempty and must not be an option')
|
|
87
|
-
base = _git(repo, 'merge-base', base_rev, head).decode().strip()
|
|
88
|
-
head_oid = _git(repo, 'rev-parse', '--verify', head + '^{commit}').decode().strip()
|
|
89
|
-
committed = set(_changed_names(_git(repo, 'diff', '--no-renames', '--name-only', '-z', base, head_oid)))
|
|
90
|
-
dirty = set()
|
|
91
|
-
if working:
|
|
92
|
-
dirty.update(_changed_names(_git(repo, 'diff', '--no-renames', '--name-only', '-z', head_oid)))
|
|
93
|
-
dirty.update(_changed_names(_git(repo, 'ls-files', '--others', '--exclude-standard', '-z')))
|
|
94
|
-
if _git(repo, 'ls-files', '-u'):
|
|
95
|
-
raise ValueError('the index has unmerged entries')
|
|
96
|
-
return {'baseOid': base, 'headOid': head_oid,
|
|
97
|
-
'committedPaths': len(committed), 'worktreePaths': len(dirty),
|
|
98
|
-
'paths': sorted(committed | dirty)}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
def memory_publication_path(path):
|
|
102
|
-
"""Whether `path` is in the memory publication set (the engine's glob semantics)."""
|
|
103
|
-
path = path.strip('/')
|
|
104
|
-
for pattern in MEMORY_PUBLICATION_SET:
|
|
105
|
-
if pattern.endswith('/**'):
|
|
106
|
-
prefix = pattern[:-3]
|
|
107
|
-
if path == prefix or path.startswith(prefix + '/'):
|
|
108
|
-
return True
|
|
109
|
-
elif path == pattern:
|
|
110
|
-
return True
|
|
111
|
-
return False
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
def _tree_modes(repo, rev, paths):
|
|
115
|
-
"""{path: git mode} of the entries `paths` name in `rev` (absent paths are omitted)."""
|
|
116
|
-
out = _git(repo, '--literal-pathspecs', 'ls-tree', '-z', '--full-tree', rev, '--', *paths)
|
|
117
|
-
modes = {}
|
|
118
|
-
for record in out.split(b'\0'):
|
|
119
|
-
if record:
|
|
120
|
-
meta, name = record.split(b'\t', 1)
|
|
121
|
-
modes[name.decode('utf-8', errors='strict')] = meta.split()[0].decode()
|
|
122
|
-
return modes
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def irregular_memory_paths(repo, base, head_oid, paths, *, working=True):
|
|
126
|
-
"""The memory paths that are not a regular file (or absent) at the base, at the head,
|
|
127
|
-
or (with `working`) in the working tree: the file types the publication set does not define."""
|
|
128
|
-
irregular = set()
|
|
129
|
-
for rev in (base, head_oid):
|
|
130
|
-
irregular.update(name for name, mode in _tree_modes(repo, rev, paths).items()
|
|
131
|
-
if mode not in REGULAR_MODES)
|
|
132
|
-
if working:
|
|
133
|
-
for path in paths:
|
|
134
|
-
target = Path(repo) / path
|
|
135
|
-
if target.is_symlink() or (target.exists() and not target.is_file()):
|
|
136
|
-
irregular.add(path)
|
|
137
|
-
return sorted(irregular & set(paths))
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
def _blob_prefixes(repo, rev, paths):
|
|
141
|
-
"""{path: its first two bytes} for the blobs `paths` name in `rev`, in one git call."""
|
|
142
|
-
if not paths:
|
|
143
|
-
return {}
|
|
144
|
-
request = b''.join(f'{rev}:{path}\n'.encode('utf-8') for path in paths)
|
|
145
|
-
proc = subprocess.run(['git', '--no-optional-locks', '-C', str(repo), 'cat-file', '--batch'],
|
|
146
|
-
input=request, capture_output=True)
|
|
147
|
-
if proc.returncode:
|
|
148
|
-
raise ValueError('git cat-file failed: ' + proc.stderr.decode(errors='replace').strip())
|
|
149
|
-
out, offset, prefixes = proc.stdout, 0, {}
|
|
150
|
-
for path in paths:
|
|
151
|
-
end = out.index(b'\n', offset)
|
|
152
|
-
header = out[offset:end].split()
|
|
153
|
-
if len(header) != 3 or header[1] != b'blob':
|
|
154
|
-
raise ValueError('git cat-file returned no blob for ' + path)
|
|
155
|
-
size = int(header[2])
|
|
156
|
-
prefixes[path] = out[end + 1:end + 1 + min(size, 2)]
|
|
157
|
-
offset = end + 1 + size + 1
|
|
158
|
-
return prefixes
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
def ineligible_instruction_paths(repo, base, head_oid, paths, *, working=True):
|
|
162
|
-
"""The instruction paths that are not a non-executable regular file without a
|
|
163
|
-
`#!` first line at the base, at the head, or (with `working`) on disk. Absence
|
|
164
|
-
on any side is eligible. With `working=False` only the two commits are read."""
|
|
165
|
-
paths = sorted(p for p in paths if _sane(p) and _instruction_class(p) == 'instruction')
|
|
166
|
-
if not paths:
|
|
167
|
-
return []
|
|
168
|
-
ineligible = set()
|
|
169
|
-
for rev in (base, head_oid):
|
|
170
|
-
modes = _tree_modes(repo, rev, paths)
|
|
171
|
-
ineligible.update(name for name, mode in modes.items() if mode not in INSTRUCTION_MODES)
|
|
172
|
-
regular = sorted(name for name, mode in modes.items() if mode in INSTRUCTION_MODES)
|
|
173
|
-
ineligible.update(name for name, prefix in _blob_prefixes(repo, rev, regular).items()
|
|
174
|
-
if prefix == b'#!')
|
|
175
|
-
if working:
|
|
176
|
-
for path in paths:
|
|
177
|
-
target = Path(repo) / path
|
|
178
|
-
if target.is_symlink():
|
|
179
|
-
ineligible.add(path)
|
|
180
|
-
elif target.exists():
|
|
181
|
-
if not target.is_file() or target.stat().st_mode & 0o111:
|
|
182
|
-
ineligible.add(path)
|
|
183
|
-
else:
|
|
184
|
-
with target.open('rb') as handle:
|
|
185
|
-
if handle.read(2) == b'#!':
|
|
186
|
-
ineligible.add(path)
|
|
187
|
-
return sorted(ineligible & set(paths))
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
def _memory_only(paths, irregular):
|
|
191
|
-
"""A memory-only candidate: every path in the publication set, each a regular file."""
|
|
192
|
-
return (irregular is not None and bool(paths) and not irregular
|
|
193
|
-
and all(memory_publication_path(p) and _sane(p) for p in paths))
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
def _sane(path):
|
|
197
|
-
p = PurePosixPath(path)
|
|
198
|
-
return not (p.is_absolute() or '..' in p.parts or any(c.isspace() for c in path))
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
def policy_digest(repo):
|
|
202
|
-
return 'sha256:' + hashlib.sha256(
|
|
203
|
-
(Path(repo) / 'bin/_lib_merge_gate.py').read_bytes()).hexdigest()
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
def _document(path):
|
|
207
|
-
return path in ('README.md', 'CHANGELOG.md') or path in EXECUTION_PLAN_PATHS or (
|
|
208
|
-
path.startswith('docs/commands/') and path.endswith('.md'))
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
def _frontend_test(path):
|
|
212
|
-
return path.startswith('dashboard/web/src/') and path.endswith(('.test.ts', '.test.tsx'))
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
def _instruction_class(path):
|
|
216
|
-
"""'instruction' for an instruction path, a full-selection reason for an
|
|
217
|
-
instruction-file name at an unreviewed location, or None for any other path."""
|
|
218
|
-
if path.endswith('.md') and path.startswith(INSTRUCTION_TREES):
|
|
219
|
-
return 'instruction'
|
|
220
|
-
if PurePosixPath(path).name in INSTRUCTION_NAMES:
|
|
221
|
-
if path in INSTRUCTION_NAMES or path in NESTED_INSTRUCTION_FILES:
|
|
222
|
-
return 'instruction'
|
|
223
|
-
return 'unreviewed nested instruction file: ' + path
|
|
224
|
-
if path in INSTRUCTION_INPUTS:
|
|
225
|
-
return 'instruction'
|
|
226
|
-
return None
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
def select(repo, paths, *, irregular=None, instruction_evidence=None):
|
|
230
|
-
"""The reviewed selection of `paths`.
|
|
231
|
-
|
|
232
|
-
`irregular` is the list of memory paths that are not regular files
|
|
233
|
-
(`irregular_memory_paths`); only a caller that computed it can have a
|
|
234
|
-
candidate selected as memory-only. Any other candidate is selected over its
|
|
235
|
-
whole diff, where a memory path is unclassified.
|
|
236
|
-
|
|
237
|
-
`instruction_evidence` is the list of instruction paths that are not
|
|
238
|
-
non-executable regular files (`ineligible_instruction_paths`); only a caller
|
|
239
|
-
that computed it can have an instruction path selected focused.
|
|
240
|
-
"""
|
|
241
|
-
repo = Path(repo)
|
|
242
|
-
manifest = json.loads((repo / 'tests/authoritative-test-manifest.json').read_text())
|
|
243
|
-
private = (repo / '.mirror-allowlist').exists()
|
|
244
|
-
names = [r['name'] for r in manifest['harnesses']
|
|
245
|
-
if private or r.get('visibility', 'public') == 'public']
|
|
246
|
-
if not names or len(names) != len(set(names)):
|
|
247
|
-
raise ValueError('invalid harness manifest')
|
|
248
|
-
paths = sorted(set(paths))
|
|
249
|
-
reasons, components = [], set()
|
|
250
|
-
memory = _memory_only(paths, irregular)
|
|
251
|
-
if memory:
|
|
252
|
-
components.add('memory')
|
|
253
|
-
for path in ([] if memory else paths):
|
|
254
|
-
p = PurePosixPath(path)
|
|
255
|
-
if path in (irregular or ()):
|
|
256
|
-
reasons.append('memory path that is not a regular file: ' + path)
|
|
257
|
-
elif p.is_absolute() or '..' in p.parts or any(c.isspace() for c in path):
|
|
258
|
-
reasons.append('unclassified path: ' + path)
|
|
259
|
-
elif '__pycache__' in p.parts:
|
|
260
|
-
# Terminal: the skill comparison never reads cache content, so no
|
|
261
|
-
# class may admit it (the memory-only shortcut is decided above).
|
|
262
|
-
reasons.append('runtime cache path: ' + path)
|
|
263
|
-
elif (instruction := _instruction_class(path)) is not None:
|
|
264
|
-
if instruction != 'instruction':
|
|
265
|
-
reasons.append(instruction)
|
|
266
|
-
elif instruction_evidence is None:
|
|
267
|
-
reasons.append('instruction path without file evidence: ' + path)
|
|
268
|
-
elif path in instruction_evidence:
|
|
269
|
-
reasons.append('instruction path that is not a non-executable regular file: ' + path)
|
|
270
|
-
else:
|
|
271
|
-
components.add('instructions')
|
|
272
|
-
elif _document(path):
|
|
273
|
-
components.add('documentation')
|
|
274
|
-
elif path in PRESENTATION_FILES or _frontend_test(path):
|
|
275
|
-
components.add('presentation')
|
|
276
|
-
elif path.startswith('dashboard/static/'):
|
|
277
|
-
components.add('presentation')
|
|
278
|
-
elif path in PRESENTATION_PYTEST:
|
|
279
|
-
components.add('presentation')
|
|
280
|
-
else:
|
|
281
|
-
reasons.append('shared, high-risk, or unclassified path: ' + path)
|
|
282
|
-
if 'instructions' in components and 'presentation' in components:
|
|
283
|
-
reasons.append('instruction text and presentation are not certified together')
|
|
284
|
-
harnesses = {'doc-lint'}
|
|
285
|
-
files = set(SMOKE_FILES)
|
|
286
|
-
if 'presentation' in components:
|
|
287
|
-
harnesses.add('frontend')
|
|
288
|
-
files.update(PRESENTATION_PYTEST)
|
|
289
|
-
if 'memory' in components:
|
|
290
|
-
files.update(MEMORY_PYTEST)
|
|
291
|
-
if 'instructions' in components:
|
|
292
|
-
files.update(INSTRUCTIONS_PYTEST)
|
|
293
|
-
if not harnesses <= set(names):
|
|
294
|
-
reasons.append('required merge harness absent from manifest')
|
|
295
|
-
if any(not (repo / p).is_file() for p in files):
|
|
296
|
-
reasons.append('required merge pytest file absent')
|
|
297
|
-
full = bool(reasons)
|
|
298
|
-
return {
|
|
299
|
-
'mode': 'full' if full else 'merge-focused',
|
|
300
|
-
'pytest': 'full' if full else 'selected',
|
|
301
|
-
'selectedHarnesses': [n for n in names if full or n in harnesses],
|
|
302
|
-
'omittedHarnesses': [n for n in names if not full and n not in harnesses],
|
|
303
|
-
'selectedPytestFiles': [] if full else sorted(files),
|
|
304
|
-
'components': sorted(components), 'reasons': reasons,
|
|
305
|
-
'policyDigest': policy_digest(repo),
|
|
306
|
-
'maxWallSeconds': MAX_SECONDS,
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
def plan(repo, base_rev, head='HEAD', *, working=True):
|
|
311
|
-
b = basis(repo, base_rev, head, working=working)
|
|
312
|
-
irregular = None
|
|
313
|
-
if b['paths'] and all(memory_publication_path(p) for p in b['paths']):
|
|
314
|
-
irregular = irregular_memory_paths(repo, b['baseOid'], b['headOid'], b['paths'], working=working)
|
|
315
|
-
evidence = None
|
|
316
|
-
if any(_sane(p) and _instruction_class(p) == 'instruction' for p in b['paths']):
|
|
317
|
-
evidence = ineligible_instruction_paths(repo, b['baseOid'], b['headOid'], b['paths'],
|
|
318
|
-
working=working)
|
|
319
|
-
result = select(repo, b['paths'], irregular=irregular, instruction_evidence=evidence)
|
|
320
|
-
result['mergeBasis'] = b
|
|
321
|
-
return result
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
def filter_legs(plan_record, directory, quarantined=()):
|
|
325
|
-
"""Narrow both expected-node legs to selected files; retain serial ownership.
|
|
326
|
-
|
|
327
|
-
bin/cctally-test-all applies tests/quarantine.json to the legs first, so a
|
|
328
|
-
selected file whose every node is quarantined has none left. Such a file
|
|
329
|
-
(one that ``quarantined``, the list's node ids, names) contributes no
|
|
330
|
-
targets; any other selected file without a recorded node refuses."""
|
|
331
|
-
directory = Path(directory)
|
|
332
|
-
selected = set(plan_record['selectedPytestFiles'])
|
|
333
|
-
found = set()
|
|
334
|
-
for name in ('pytest', 'benchmark'):
|
|
335
|
-
path = directory / (name + '.txt')
|
|
336
|
-
nodes = [n for n in path.read_text().splitlines() if n.split('::')[0] in selected]
|
|
337
|
-
found.update(n.split('::')[0] for n in nodes)
|
|
338
|
-
path.write_text(''.join(n + '\n' for n in nodes))
|
|
339
|
-
absent = selected - found - {node.split('::')[0] for node in quarantined}
|
|
340
|
-
if absent:
|
|
341
|
-
raise ValueError('selected files absent from recorded pytest estate: ' + ', '.join(sorted(absent)))
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
def quarantine_ids(repo):
|
|
345
|
-
"""The pytest node ids tests/quarantine.json lists; none when the tree carries no list.
|
|
346
|
-
|
|
347
|
-
Parsed by the shared bin/_lib_quarantine.py; harness cases are not pytest
|
|
348
|
-
nodes and are left to their harness. bin/cctally-test-all validated the
|
|
349
|
-
list at admission, before this runs."""
|
|
350
|
-
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
351
|
-
import _lib_quarantine
|
|
352
|
-
return _lib_quarantine.pytest_ids(_lib_quarantine.load(repo))
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
def supervise(command, seconds):
|
|
356
|
-
"""Bound the complete gate, including foreground admission subprocesses.
|
|
357
|
-
|
|
358
|
-
A fresh POSIX session contains the aggregator's separate pool/pytest
|
|
359
|
-
process groups. Terminating that session also reaches children when bash
|
|
360
|
-
is waiting on an admission command and cannot yet run its signal trap.
|
|
361
|
-
The caller writes the ordinary contract's timeout verdict after teardown.
|
|
362
|
-
"""
|
|
363
|
-
process = subprocess.Popen(command, start_new_session=True)
|
|
364
|
-
|
|
365
|
-
def members():
|
|
366
|
-
listing = subprocess.check_output(['ps', '-A', '-o', 'pid='], text=True)
|
|
367
|
-
result = []
|
|
368
|
-
for token in listing.split():
|
|
369
|
-
pid = int(token)
|
|
370
|
-
try:
|
|
371
|
-
if os.getsid(pid) == process.pid:
|
|
372
|
-
result.append(pid)
|
|
373
|
-
except (ProcessLookupError, PermissionError):
|
|
374
|
-
pass
|
|
375
|
-
return result
|
|
376
|
-
|
|
377
|
-
def terminate():
|
|
378
|
-
for sig in (signal.SIGTERM, signal.SIGKILL):
|
|
379
|
-
for pid in members():
|
|
380
|
-
try:
|
|
381
|
-
os.kill(pid, sig)
|
|
382
|
-
except ProcessLookupError:
|
|
383
|
-
pass
|
|
384
|
-
if sig == signal.SIGTERM:
|
|
385
|
-
try:
|
|
386
|
-
process.wait(timeout=2)
|
|
387
|
-
except subprocess.TimeoutExpired:
|
|
388
|
-
pass
|
|
389
|
-
process.wait()
|
|
390
|
-
|
|
391
|
-
def interrupted(signum, _frame):
|
|
392
|
-
terminate()
|
|
393
|
-
raise SystemExit(128 + signum)
|
|
394
|
-
|
|
395
|
-
old = {sig: signal.signal(sig, interrupted) for sig in (signal.SIGTERM, signal.SIGINT)}
|
|
396
|
-
try:
|
|
397
|
-
try:
|
|
398
|
-
return process.wait(timeout=max(0, seconds))
|
|
399
|
-
except subprocess.TimeoutExpired:
|
|
400
|
-
terminate()
|
|
401
|
-
return 124
|
|
402
|
-
finally:
|
|
403
|
-
for sig, handler in old.items():
|
|
404
|
-
signal.signal(sig, handler)
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
def main(argv=None):
|
|
408
|
-
parser = argparse.ArgumentParser(description=__doc__)
|
|
409
|
-
parser.add_argument('--repo', default=str(Path(__file__).resolve().parents[1]))
|
|
410
|
-
parser.add_argument('--base')
|
|
411
|
-
parser.add_argument('--required-mode', action='store_true')
|
|
412
|
-
parser.add_argument('--shell', action='store_true')
|
|
413
|
-
parser.add_argument('--filter-legs')
|
|
414
|
-
parser.add_argument('--deadline', nargs=argparse.REMAINDER,
|
|
415
|
-
help=argparse.SUPPRESS)
|
|
416
|
-
args = parser.parse_args(argv)
|
|
417
|
-
if args.deadline is not None:
|
|
418
|
-
if len(args.deadline) < 2:
|
|
419
|
-
parser.error('deadline requires seconds and a command')
|
|
420
|
-
return supervise(args.deadline[1:], int(args.deadline[0]))
|
|
421
|
-
if not args.base:
|
|
422
|
-
parser.error('--base is required')
|
|
423
|
-
try:
|
|
424
|
-
result = plan(args.repo, args.base)
|
|
425
|
-
if args.required_mode:
|
|
426
|
-
# `<mode> <reason>`: the wrapper decides on the mode alone; the
|
|
427
|
-
# reason names the focused components for whoever reads the log.
|
|
428
|
-
if result['mode'] == 'full':
|
|
429
|
-
reason = 'reviewed-selection'
|
|
430
|
-
else:
|
|
431
|
-
reason = '+'.join(result['components']) or 'none'
|
|
432
|
-
print(f"{result['mode']} {reason}")
|
|
433
|
-
elif args.filter_legs:
|
|
434
|
-
filter_legs(result, args.filter_legs, quarantined=quarantine_ids(args.repo))
|
|
435
|
-
elif args.shell:
|
|
436
|
-
print('mode\t' + result['mode'])
|
|
437
|
-
print('harnesses\t' + ' '.join(result['selectedHarnesses']))
|
|
438
|
-
print('omitted\t' + ' '.join(result['omittedHarnesses']))
|
|
439
|
-
print('pytest\t' + result['pytest'])
|
|
440
|
-
print('files\t' + ' '.join(result['selectedPytestFiles']))
|
|
441
|
-
print('seconds\t' + str(result['maxWallSeconds']))
|
|
442
|
-
print('record\t' + json.dumps(result, sort_keys=True, separators=(',', ':')))
|
|
443
|
-
else:
|
|
444
|
-
print(json.dumps(result, sort_keys=True, indent=2))
|
|
445
|
-
except (ValueError, OSError, KeyError, UnicodeError) as exc:
|
|
446
|
-
print('merge-gate: ' + str(exc), file=sys.stderr)
|
|
447
|
-
return 2
|
|
448
|
-
return 0
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
if __name__ == '__main__':
|
|
452
|
-
raise SystemExit(main())
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{Ft as e,Rt as t,a as n,b as r,c as i,f as a,t as o,x as s}from"./useKeymap-CW7Up0Ay.js";import{dt as c,jt as l,o as u,s as d,ut as f}from"./index-BXDOzSng.js";var p=t(e(),1);function m(){let[e,t]=(0,p.useState)(null),[n,r]=(0,p.useState)(!1),[i,a]=(0,p.useState)(null);return{report:e,loading:n,error:i,refresh:(0,p.useCallback)(async()=>{r(!0),a(null);try{let e=await fetch(`/api/doctor`);if(!e.ok)throw Error(`HTTP ${e.status}`);t(await e.json())}catch(e){a(e instanceof Error?e.message:String(e))}finally{r(!1)}},[])}}var h=n(),g={ok:`✓`,warn:`⚠`,fail:`✗`},_=/(--[A-Za-z0-9][A-Za-z0-9-]*)/g;function v({text:e}){return(0,h.jsx)(h.Fragment,{children:e.split(_).map((e,t)=>e.startsWith(`--`)?(0,h.jsx)(`span`,{className:`doctor-modal__flag`,children:e},`${e}-${t}`):e)})}function y(){let e=(0,p.useSyncExternalStore)(r,()=>a().doctorModalOpen),{report:t,loading:n,error:l,refresh:g}=m(),_=()=>{i({type:`CLOSE_DOCTOR_MODAL`})};o((0,p.useMemo)(()=>[{key:`Escape`,scope:`modal`,action:_,when:()=>a().doctorModalOpen}],[])),(0,p.useEffect)(()=>{e&&g()},[e,g]),(0,p.useEffect)(()=>{if(!t)return;let e=a().doctor,n=e?Date.parse(e.generated_at):NaN,r=Date.parse(t.generated_at);e&&Number.isFinite(n)&&Number.isFinite(r)&&r<=n||i({type:`SET_DOCTOR_AGGREGATE`,doctor:{severity:t.overall.severity,counts:t.overall.counts,generated_at:t.generated_at,fingerprint:`client-reconcile`}})},[t]);let v=(0,p.useRef)(null);return c(v,{active:e,trapEnabled:(0,p.useSyncExternalStore)(r,()=>s(a())===`doctor`),initialFocus:`container`}),f(e),e?(0,h.jsxs)(`div`,{className:`update-modal-root`,onClick:_,children:[(0,h.jsx)(`div`,{className:`modal-backdrop`}),(0,h.jsxs)(`div`,{ref:v,className:`modal-card doctor-modal-card`,role:`dialog`,"aria-modal":`true`,"aria-labelledby":`doctor-modal-title`,tabIndex:-1,onClick:e=>e.stopPropagation(),children:[(0,h.jsx)(u,{title:`Doctor`,titleId:`doctor-modal-title`,headerExtras:(0,h.jsxs)(`div`,{className:`doctor-modal__header-actions`,children:[(0,h.jsx)(`button`,{type:`button`,className:`doctor-modal__refresh`,onClick:()=>{g()},disabled:n,"aria-label":`Refresh doctor report`,children:n?`refreshing…`:`↻ refresh`}),(0,h.jsx)(d,{onClose:_})]})}),(0,h.jsxs)(`div`,{className:`modal-body`,children:[n&&!t&&(0,h.jsx)(`p`,{children:`Loading…`}),l&&(0,h.jsxs)(`p`,{className:`doctor-modal__error`,children:[`Error loading report: `,l]}),t&&(0,h.jsx)(b,{report:t})]})]})]}):null}function b({report:e}){let{counts:t}=e.overall;return(0,h.jsxs)(h.Fragment,{children:[(0,h.jsxs)(`p`,{className:`doctor-modal__summary`,children:[t.ok,` OK · `,t.warn,` WARN · `,t.fail,` FAIL`]}),e.categories.map(e=>(0,h.jsx)(x,{cat:e,defaultOpen:e.severity!==`ok`},e.id))]})}function x({cat:e,defaultOpen:t}){let[n,r]=(0,p.useState)(t);return(0,h.jsxs)(`section`,{className:`doctor-modal__category doctor-modal__category--${e.severity}`,children:[(0,h.jsxs)(`button`,{type:`button`,className:`doctor-modal__category-header`,onClick:()=>r(e=>!e),"aria-expanded":n,children:[(0,h.jsx)(`span`,{className:`doctor-modal__category-caret`,"aria-hidden":`true`,children:n?`▾`:`▸`}),(0,h.jsx)(`span`,{className:`doctor-modal__glyph`,"aria-hidden":`true`,children:g[e.severity]}),(0,h.jsx)(`span`,{children:e.title})]}),n&&e.checks.map(e=>(0,h.jsx)(S,{c:e},e.id))]})}function S({c:e}){let[t,n]=(0,p.useState)(!1),r=e.details&&Object.keys(e.details).length>0,i=e.id===`data.latest_snapshot_age`&&typeof e.details?.latest_snapshot_age_s==`number`?l(e.details.latest_snapshot_age_s):e.summary;return(0,h.jsxs)(`div`,{className:`doctor-modal__check doctor-modal__check--${e.severity}`,children:[(0,h.jsxs)(`p`,{children:[(0,h.jsx)(`span`,{className:`doctor-modal__glyph`,"aria-label":e.severity,children:g[e.severity]}),` `,(0,h.jsx)(`strong`,{children:e.title}),`: `,i]}),e.remediation&&(0,h.jsxs)(`p`,{className:`doctor-modal__remediation`,children:[`→ `,(0,h.jsx)(v,{text:e.remediation})]}),e.severity!==`ok`&&!e.remediation&&(0,h.jsxs)(`p`,{className:`doctor-modal__remediation`,children:[`→ Run `,(0,h.jsx)(`code`,{children:`cctally doctor`}),` for the full report`]}),r&&(0,h.jsxs)(h.Fragment,{children:[(0,h.jsxs)(`button`,{type:`button`,className:`doctor-modal__details-toggle`,onClick:()=>n(e=>!e),"aria-expanded":t,children:[t?`▼`:`▶`,` details`]}),t&&(0,h.jsx)(`pre`,{className:`doctor-modal__details`,children:JSON.stringify(e.details,null,2)})]})]})}export{y as DoctorModal};
|