@tomflow/chatloop-extension 0.3.47 → 0.3.48

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.
@@ -23,20 +23,7 @@
23
23
  if (standalone.length !== 1) return "UNKNOWN";
24
24
  return match[1];
25
25
  }
26
- function fingerprint(text) {
27
- let hash = 2166136261;
28
- for (let i = 0; i < text.length; i++) {
29
- hash ^= text.charCodeAt(i);
30
- hash = Math.imul(hash, 16777619);
31
- }
32
- return (hash >>> 0).toString(16) + ":" + text.length;
33
- }
34
- function decision(status, wasConfirming = false) {
35
- if (status === "DONE") return "COMPLETED";
36
- if (status === "BLOCKED") return "BLOCKED";
37
- if (status === "CONTINUE") return "CONTINUE";
38
- if (status === "HANDOFF") return "HANDOFF";
39
- return wasConfirming ? "BLOCKED" : "CONFIRM";
40
- }
41
- globalThis.ChatLoopCoreV1 = Object.freeze({parseStatus, fingerprint, decision});
26
+ // Worker is the sole status consumer; observation fingerprints belong to
27
+ // observer.js and dispatch decisions belong to background.js.
28
+ globalThis.ChatLoopCoreV1 = Object.freeze({parseStatus});
42
29
  })();
@@ -4,12 +4,12 @@
4
4
  const KEY = 'chat-loop.resources.v1';
5
5
  const ACTION_LIMIT = 3; // Includes machine Eye, Start, manual and timed Actions.
6
6
  const CHAT_LIMIT = 2; // One owner plus at most one Handoff successor.
7
- const AUDIT_TTL = 60_000;
7
+ const AUDIT_TTL = 60_000; // Reap obsolete audit pages from installed older Extension versions.
8
8
  const READ_TTL = 180_000;
9
9
  const TERMINAL_TTL = 30_000;
10
10
  const READ_ONLY = new Set(['status','text','dom','screenshot','reload']);
11
11
  const ACTIONS = new Set(['start','continue','handoff','status','text','dom',
12
- 'screenshot','reload','clean','clock']);
12
+ 'screenshot','reload','clean']);
13
13
  const validId = s => /^[a-f0-9]{32}$/.test(s || '');
14
14
  const validTabId = s => /^[1-9][0-9]*$/.test(s || '');
15
15
  const extensionBase = () => chrome.runtime.getURL('');
@@ -20,15 +20,8 @@
20
20
  if (u.protocol !== 'chrome-extension:' || !tab.url.startsWith(extensionBase())
21
21
  || u.host !== new URL(extensionBase()).host) return null;
22
22
  if (u.pathname === '/popup.html' && u.search === '?audit=1')
23
- return {kind:'audit'};
24
- if (u.pathname === '/popup.html' && u.searchParams.size === 1) {
25
- const name=[...u.searchParams.keys()][0],value=u.searchParams.get(name);
26
- const noId=new Set(['newTest','cleanup','cleanupVerified','cleanupStaleMachine']);
27
- const tabId=new Set(['cleanupTestHome','cleanupFailedStartHome','cleanupBlockedE2E']);
28
- if ((noId.has(name)&&value==='1') || (tabId.has(name)&&validTabId(value)))
29
- return {kind:'manual',name:'acceptance'};
30
- }
31
- const name = u.pathname.match(/^\/(start|continue|handoff|status|text|dom|screenshot|reload|clean|clock)\.html$/)?.[1];
23
+ return {kind:'audit'}; // Legacy page reaping only; old audit UI is not executable.
24
+ const name = u.pathname.match(/^\/([a-z]+)\.html$/)?.[1];
32
25
  if (!ACTIONS.has(name)) return null;
33
26
  if (u.searchParams.size === 1 && validId(u.searchParams.get('requestId')))
34
27
  return {kind:READ_ONLY.has(name) || ['continue','handoff'].includes(name)
@@ -178,11 +171,12 @@
178
171
  :{ok:true,actionCount,chatCount};
179
172
  }
180
173
  async function registerAction(tab) {
181
- if (!classify(tab)) return false;
174
+ const info=classify(tab);
175
+ if (!info) return false;
182
176
  const state=await load();
183
177
  if (!state.entries.some(e=>e.id===tab.id)) {
184
178
  state.entries.push({id:tab.id,url:tab.url,kind:'action',
185
- type:classify(tab).kind,firstSeenAt:Date.now(),owned:true});
179
+ type:info.kind,firstSeenAt:Date.now(),owned:true});
186
180
  state.created++;
187
181
  // Fast actions can finish before the next alarm/reconciliation. Count
188
182
  // their observed creation in peak metrics even if no later scan sees them.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "Chat Loop Extension",
4
- "version": "0.3.47",
4
+ "version": "0.3.48",
5
5
  "description": "Chat Loop browser companion: Eye actions, Turn observer, Continue and Handoff Actions",
6
6
  "permissions": [
7
7
  "activeTab",
@@ -21,6 +21,5 @@
21
21
  <p><a href="https://chatgpt.com/" target="_blank" rel="noopener noreferrer">打开 ChatGPT 网页版</a></p>
22
22
  <p id="action-state" role="status">最近发送动作:读取中…</p>
23
23
  <script src="popup.js"></script>
24
- <script src="acceptance.js"></script>
25
24
  </body>
26
25
  </html>
@@ -55,7 +55,7 @@ async function showActionState() {
55
55
  const key = "chat-loop.action.run.v1";
56
56
  const run = (await chrome.storage.local.get(key))[key];
57
57
  const allowed = ["phase", "action", "reason", "tabId", "page", "sourceTabId", "sourcePage",
58
- "userKey", "assistantKey", "newUserKey", "testSetup", "startedAt",
58
+ "userKey", "assistantKey", "newUserKey", "startedAt",
59
59
  "sessionId", "projectId", "generation",
60
60
  "deadlineAt", "handoffPending", "handoffPendingAt", "attemptedNewTabId"];
61
61
  const summary = {version: chrome.runtime.getManifest().version};
package/lib/bridge.mjs CHANGED
@@ -23,7 +23,7 @@ export function requestDir(id) {
23
23
  if(typeof id!=='string'||!ID.test(id))throw Object.assign(Error('Invalid request ID'),{code:'INVALID_REQUEST_ID'});
24
24
  return join(tempRoot(),id);
25
25
  }
26
- export function validateIntent(action, intent) {
26
+ function validateIntent(action, intent) {
27
27
  if(action==='start'){
28
28
  if(!intent||typeof intent!=='object'||Array.isArray(intent)
29
29
  ||Object.keys(intent).some(k=>!['projectId','prompt','confirmed','replaceBlockedSessionId'].includes(k))
@@ -138,15 +138,6 @@ export function readResult(id) {
138
138
  privateDir(requestDir(id));
139
139
  return JSON.parse(readFileSync(p,'utf8'));
140
140
  }
141
- // Read-only cleanup proof. Only an aged, durably FAILED machine request
142
- // can qualify; never expose the nonce, original intent, or result contents.
143
- export function staleFailureConfirmed(id,action) {
144
- if(!ACTIONS.includes(action))return false;
145
- const result=readResult(id);
146
- return !!(result && result.id===id && result.action===action
147
- && result.status==='FAILED' && Number.isSafeInteger(result.at)
148
- && result.at<=Date.now()-TTL_MS);
149
- }
150
141
  export function cleanup(){
151
142
  const root=tempRoot();
152
143
  if(!existsSync(root))return;
@@ -8,7 +8,7 @@ import {randomUUID} from 'node:crypto';
8
8
  const ID=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
9
9
  const CHAT=/^[0-9a-f-]{12,}$/i;
10
10
  const PROJECT=/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/;
11
- const PHASE=new Set(['STARTING','RESERVED','PENDING','WAITING_REPLY','WAITING_INTERVAL','DONE','BLOCKED','WALL_CLOCK_HOLD']);
11
+ const PHASE=new Set(['STARTING','RESERVED','PENDING','WAITING_REPLY','DONE','BLOCKED']);
12
12
  const fail=code=>Object.assign(Error(code),{code});
13
13
  export const sessionPath=()=>join(homedir(),'.chat-loop','session','active-session.json');
14
14
  const ensurePrivate=dir=>{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomflow/chatloop-extension",
3
- "version": "0.3.47",
3
+ "version": "0.3.48",
4
4
  "type": "module",
5
5
  "description": "Chat Loop Extension package: nine formal Action pages and its own native CLI bridge",
6
6
  "bin": {