@awak-app/simy-cli 0.7.16 → 0.7.18
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/README.md +180 -26
- package/package.json +3 -2
- package/src/agent.js +128 -7
- package/src/bounded-local-task-subtask-pool.js +32 -6
- package/src/bounded-local-task-subtasks-contract.js +1 -1
- package/src/cli-contract.js +1 -1
- package/src/codex-plugins/simy/.codex-plugin/plugin.json +2 -2
- package/src/codex-plugins/simy/hooks/README.md +8 -3
- package/src/codex-plugins/simy/hooks/delivery-loop.mjs +261 -67
- package/src/codex-plugins/simy/hooks/hooks.json +1 -1
- package/src/codex-plugins/simy/hooks/loop-kernel/conformance.json +136 -0
- package/src/codex-plugins/simy/hooks/loop-kernel/index.mjs +42 -0
- package/src/codex-plugins/simy/hooks/loop-kernel/outcome-review.mjs +31 -0
- package/src/codex-plugins/simy/hooks/loop-kernel/pin.json +6 -0
- package/src/codex-plugins/simy/hooks/loop-kernel/policy.json +141 -0
- package/src/codex-plugins/simy/hooks/loop-kernel/task-pool.mjs +34 -0
- package/src/codex-plugins/simy/hooks/loop-kernel/work-frontier.mjs +132 -0
- package/src/codex-plugins/simy/hooks/loop-kernel.mjs +6 -0
- package/src/codex-plugins/simy/hooks/outcome-progress.mjs +15 -3
- package/src/codex-plugins/simy/hooks/purpose-completion-contract.mjs +10 -0
- package/src/codex-plugins/simy/hooks/purpose-evidence.mjs +8 -6
- package/src/codex-plugins/simy/hooks/result-cycle.mjs +32 -6
- package/src/codex-plugins/simy/hooks/work-frontier.mjs +2 -0
- package/src/codex-plugins/simy/skills/diagnose/SKILL.md +10 -4
- package/src/coding-run-recovery.js +4 -2
- package/src/delivery-hooks/claude-workflow.md +10 -7
- package/src/delivery-hooks/command.js +45 -10
- package/src/delivery-hooks/consult.js +60 -0
- package/src/delivery-hooks/diagnosis.js +2 -2
- package/src/delivery-hooks/legacy-hook-routing.js +46 -8
- package/src/delivery-hooks/local-runtime.js +50 -1
- package/src/delivery-hooks/local-supervisor.js +1 -1
- package/src/delivery-hooks/repair-continuation.js +80 -0
- package/src/delivery-hooks/repair.js +164 -0
- package/src/delivery-hooks/supervisor-service.js +3 -1
- package/src/delivery-hooks/supervisor.js +88 -12
- package/src/desktop-access.js +2 -1
- package/src/desktop-host.js +62 -2
- package/src/durable-local-task-worker.js +372 -58
- package/src/execution-capability-contract.js +15 -1
- package/src/index.js +3 -3
- package/src/local-photos-read.swift +33 -0
- package/src/local-photos.js +47 -0
- package/src/local-task-attachment-store.js +31 -0
- package/src/local-task-destination.js +174 -0
- package/src/local-task.js +119 -7
- package/src/native-delegation-contract.js +68 -0
- package/src/native-provider-identity.js +60 -0
- package/src/orchestrator/budget.js +22 -11
- package/src/orchestrator/independent-audit.js +9 -18
- package/src/orchestrator/loop.js +27 -59
- package/src/orchestrator/recovery.js +32 -2
- package/src/provider-delegation.js +336 -0
- package/src/runner.js +2 -1
- package/src/session-supervision/artifact-observer.js +138 -0
- package/src/session-supervision/claude-sessions.js +5 -3
- package/src/session-supervision/codex-app-server.js +20 -5
- package/src/session-supervision/completion-artifacts.js +44 -0
- package/src/session-supervision/consistency-auditor.js +8 -11
- package/src/session-supervision/continuation-analysis.js +46 -28
- package/src/session-supervision/discovery-window.js +1 -1
- package/src/session-supervision/final-response-recovery.js +5 -3
- package/src/session-supervision/index.js +25 -8
- package/src/session-supervision/purpose-recovery.js +12 -3
- package/src/session-supervision/purpose-verification.js +9 -57
- package/src/session-supervision/recovery-frontier.js +55 -0
- package/src/session-supervision/remote-hosts.js +1 -1
- package/src/session-supervision/stop-notifications.js +8 -8
- package/src/sqm/agent-skill.js +1 -1
- package/src/sqm/checkers.js +12 -6
- package/src/sqm/claude-plugin-update.js +22 -8
- package/src/sqm/claude-plugin.js +4 -0
- package/src/sqm/local-tests.js +2 -2
- package/src/sqm/plugin-cache.js +67 -0
- package/src/sqm/proof.js +25 -0
- package/src/sqm/report.js +1 -0
- package/src/sqm/workflow-onboarding.js +3 -39
- package/src/sqm/workflow-update.js +17 -6
- package/src/team-status-fence-store.js +32 -0
- package/src/team-threads.js +478 -0
package/src/desktop-host.js
CHANGED
|
@@ -5,6 +5,8 @@ import { createLedgerCoordinatorAdapters } from "./update-detachment/ledger-adap
|
|
|
5
5
|
import { createUpdateCoordinator } from "./update-detachment/coordinator.js";
|
|
6
6
|
import { sessionWorkState, compareSessionWork, reconcileFamilyCompletion, expireSessionWorkState } from './session-supervision/work-state.js';
|
|
7
7
|
import { createPullRequestObserver } from './session-supervision/pull-requests.js';
|
|
8
|
+
import { createTeamThreads, teamThreadKey } from './team-threads.js';
|
|
9
|
+
import { createTeamStatusFenceStore } from './team-status-fence-store.js';
|
|
8
10
|
import { sessionDecisionPresentation } from './session-supervision/decision-presentation.js';
|
|
9
11
|
import { PROVIDER_LINKS, readProviderLinks, writeProviderLink, requireProviderLink } from "./provider-links.js";
|
|
10
12
|
import { randomUUID } from "node:crypto";
|
|
@@ -221,6 +223,7 @@ export async function startDesktopHost({ input = process.stdin, output = process
|
|
|
221
223
|
let statisticsSelection = { key: null, generation: 0 };
|
|
222
224
|
const stopNotifier = createStopNotifier({ emit: event => { if (!closed && !relay) emit(event); } });
|
|
223
225
|
if (env.SIMY_REMOTE_CHILD !== "1" && process.platform !== "win32") remoteHosts = (dependencies.createRemoteHostManager || createRemoteHostManager)({ root, onChange: () => { if (!closed && !relay) setImmediate(() => { void publish().catch(() => {}); }); } });
|
|
226
|
+
let teamThreads;
|
|
224
227
|
let currentAccess = { state: 'checking', organizationId: null, organizationName: null };
|
|
225
228
|
let nativeDevelopmentReports = { state: 'loading', enrollments: [] };
|
|
226
229
|
let nativeDevelopmentReportsScope = null;
|
|
@@ -713,6 +716,7 @@ export async function startDesktopHost({ input = process.stdin, output = process
|
|
|
713
716
|
if (JSON.stringify(await readProviderLinks(root)) !== requestedLinks) { publishAgain = true; return; }
|
|
714
717
|
if (connectionRevision !== requestedConnectionRevision || !sameAccess(sampledAccess, agent?.getDesktopAccess ? agent.getDesktopAccess() : await readAccess())) { publishAgain = true; return; }
|
|
715
718
|
status.nativeDevelopmentReports = { state: 'loading', enrollments: [] };
|
|
719
|
+
status.teamThreads = teamThreads?.snapshot();
|
|
716
720
|
if (!closed && !relay) emitStatus(status);
|
|
717
721
|
return;
|
|
718
722
|
}
|
|
@@ -764,6 +768,13 @@ export async function startDesktopHost({ input = process.stdin, output = process
|
|
|
764
768
|
status.sessionSupervision = { ...discovery, refreshing: Boolean(sessionRefresh), sessions: reconcileFamilyCompletion(sessions.map(candidate => ({ ...candidate,
|
|
765
769
|
decisionRequest: sessionDecisionPresentation(candidate, runsBySession.get(`${candidate.provider}:${candidate.session}`)),
|
|
766
770
|
workState: sessionWorkState(candidate, runsBySession.get(`${candidate.provider}:${candidate.session}`) || stateRunsBySession.get(`${candidate.provider}:${candidate.session}`), { provider: discovery.providers?.[candidate.provider] }) }))).sort(compareSessionWork) };
|
|
771
|
+
teamThreads?.tick(sessions);
|
|
772
|
+
status.teamThreads = teamThreads?.snapshot();
|
|
773
|
+
for (const session of status.sessionSupervision.sessions) {
|
|
774
|
+
const key = teamThreadKey(agent.getTeamThreadsScope?.() || {}, session);
|
|
775
|
+
const own = status.teamThreads?.own.find(item => item.threadKey === key);
|
|
776
|
+
session.teamSharing = { threadKey: key, enabled: own?.enabled === true, pendingStop: status.teamThreads?.pendingStops.includes(key) === true, confirmationRequired: status.teamThreads?.confirmationRequired.includes(key) === true };
|
|
777
|
+
}
|
|
767
778
|
const latestAccess = await accessSnapshot();
|
|
768
779
|
if (JSON.stringify(await readProviderLinks(root)) !== requestedLinks ||
|
|
769
780
|
!desktopAccessReady(latestAccess) || accessScope(latestAccess) !== requestedScope ||
|
|
@@ -779,12 +790,14 @@ export async function startDesktopHost({ input = process.stdin, output = process
|
|
|
779
790
|
if (accessScope(latestConnectionStatus?.access) !== requestedScope || !desktopAccessReady(latestConnectionStatus?.access)) { publishAgain = true; return; }
|
|
780
791
|
status = { ...structuredClone(latestConnectionStatus), deliveryHooks: status.deliveryHooks, sessionSupervision: status.sessionSupervision };
|
|
781
792
|
}
|
|
793
|
+
status.teamThreads = teamThreads?.snapshot();
|
|
782
794
|
if (!closed && !relay) emitStatus(status);
|
|
783
795
|
}).finally(() => { publishing = null; if (publishAgain && !closed) { publishAgain = false; setImmediate(() => { void publish().catch(() => {}); }); } });
|
|
784
796
|
return publishing;
|
|
785
797
|
};
|
|
786
798
|
const stopAgent = async () => {
|
|
787
799
|
clearInterval(timer);
|
|
800
|
+
teamThreads?.close();
|
|
788
801
|
pluginInspectionAbort.abort();
|
|
789
802
|
activeStatisticsRead?.controller.abort();
|
|
790
803
|
discoveryStopped = true;
|
|
@@ -843,6 +856,13 @@ export async function startDesktopHost({ input = process.stdin, output = process
|
|
|
843
856
|
},
|
|
844
857
|
});
|
|
845
858
|
if (env.SIMY_UPDATE_TRANSFER_TOKEN) await coordinator.reconnect();
|
|
859
|
+
teamThreads = createTeamThreads({
|
|
860
|
+
readScope: () => agent.getTeamThreadsScope?.() || {key: accessScope(currentAccess),allowed:false,authenticated:false},
|
|
861
|
+
request: (body,signal) => agent.requestTeamThreads(body,signal),
|
|
862
|
+
fenceStore: createTeamStatusFenceStore(root),
|
|
863
|
+
readContext: dependencies.readTeamThreadContext,
|
|
864
|
+
onChange: () => { if(!closed) setImmediate(() => {void publish().catch(() => {});}); },
|
|
865
|
+
});
|
|
846
866
|
stopWorkflows = (dependencies.startWorkflowUpdates || startWorkflowUpdates)({ enabled: env.SIMY_AUTO_UPDATE !== "0" });
|
|
847
867
|
updater.on?.("change", () => { void publish().catch(() => {}); });
|
|
848
868
|
updater.start({ registry: agent.registry, coordinator, isDesktopIdle: () => !unfinishedDesktopWork,
|
|
@@ -1105,15 +1125,39 @@ export async function startDesktopHost({ input = process.stdin, output = process
|
|
|
1105
1125
|
const commandScope = accessScope(access);
|
|
1106
1126
|
if (!desktopActionAllowed(access, command)) throw Object.assign(new Error('Desktop access is required.'), { code: 'desktop_access_required' });
|
|
1107
1127
|
const recoveryControl = ['provider_disconnect', 'session_unmonitor'].includes(action) ||
|
|
1108
|
-
['session_set_auto_continue', 'session_set_email_reports'].includes(action) && command.enabled === false;
|
|
1128
|
+
['session_set_auto_continue', 'session_set_email_reports', 'team_thread_share'].includes(action) && command.enabled === false;
|
|
1109
1129
|
if (['detach_update', 'update_reconnect'].includes(action)) requireDesktopAccess(access);
|
|
1110
1130
|
else if (!recoveryControl && desktopAccessReady(access) && !desktopActionAllowed({ state: 'unavailable' }, command)) await authorizeWork();
|
|
1111
1131
|
|
|
1112
1132
|
if (!coordinator.acceptsNewWork() && !recoveryControl && !["refresh", "reconnect", "task_detail", "check_update", "quit", "delivery_stop", "delivery_pause", "delivery_reject"].includes(action)) {
|
|
1113
1133
|
throw new Error("The update connection requires recovery.");
|
|
1114
1134
|
}
|
|
1135
|
+
if (['team_threads_refresh','team_thread_open','team_thread_share'].includes(action)) {
|
|
1136
|
+
let ok;
|
|
1137
|
+
if(action === 'team_threads_refresh') ok = await teamThreads.refresh({memberId:command.memberId});
|
|
1138
|
+
else if(action === 'team_thread_open') ok = await teamThreads.open({memberId:command.memberId,threadKey:command.threadKey});
|
|
1139
|
+
else {
|
|
1140
|
+
if (command.organizationId !== undefined && command.organizationId !== access.organizationId) throw new Error('Sharing organization changed. Confirm again.');
|
|
1141
|
+
// Publication reads this host's provider context. Never reinterpret
|
|
1142
|
+
// a remote or ambiguous identity as a same-ID local conversation.
|
|
1143
|
+
if ((command.hostId && command.hostId !== 'local') || (!command.hostId && remoteHosts?.hasSession(command.session))) {
|
|
1144
|
+
throw new Error('Team sharing requires an explicitly selected local conversation.');
|
|
1145
|
+
}
|
|
1146
|
+
const selected = sessionStatus.sessions.find(item => (!item.hostId || item.hostId === 'local') && item.provider === command.provider && item.session === command.session);
|
|
1147
|
+
if (command.enabled === false) {
|
|
1148
|
+
// Revocation uses authenticated own rows, never provider context.
|
|
1149
|
+
const key = command.threadKey ?? teamThreadKey(agent.getTeamThreadsScope(), { provider: command.provider, session: command.session });
|
|
1150
|
+
ok = await teamThreads.stopSharing(key);
|
|
1151
|
+
} else {
|
|
1152
|
+
if(!selected || command.threadKey) throw new Error('Refresh and select your conversation again.');
|
|
1153
|
+
ok = await teamThreads.setSharing(selected,command.enabled);
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
emit({type:'result',id:command.id,ok:ok===true}); void publish().catch(() => {}); return;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1115
1159
|
let commandProviderLink;
|
|
1116
|
-
if (command.provider && !["provider_connect", "provider_disconnect", "delivery_stop", "delivery_pause", "delivery_reject", "session_untrack", "session_unmonitor"].includes(action) &&
|
|
1160
|
+
if (command.provider && !["refresh", "provider_connect", "provider_disconnect", "delivery_stop", "delivery_pause", "delivery_reject", "session_untrack", "session_unmonitor"].includes(action) &&
|
|
1117
1161
|
!(action === "session_set_auto_continue" && command.enabled === false)) {
|
|
1118
1162
|
commandProviderLink = await requireProviderLink({ root: deliveryRoot, provider: command.provider });
|
|
1119
1163
|
}
|
|
@@ -1424,6 +1468,22 @@ export async function startDesktopHost({ input = process.stdin, output = process
|
|
|
1424
1468
|
await authorizeWork(commandScope);
|
|
1425
1469
|
const result = await deadlines.decide(context, { ...command, requestId: command.requestId || command.decisionId });
|
|
1426
1470
|
if (result.status === 'conflict') throw Object.assign(new Error('Deadline changed; refresh before deciding.'), { code: 'conflict' });
|
|
1471
|
+
} else if (action === "session_set_pinned") {
|
|
1472
|
+
if (typeof command.enabled !== 'boolean') throw new Error('Choose whether to pin this conversation.');
|
|
1473
|
+
const candidate = await selectedSession(command, { preferObserved: true });
|
|
1474
|
+
await authorizeWork(commandScope);
|
|
1475
|
+
const pinScope = command.pinScope ?? 'legacy';
|
|
1476
|
+
if (typeof pinScope !== 'string' || !pinScope || pinScope.length > 512) throw new Error('Invalid pin scope.');
|
|
1477
|
+
await updateRecord(deliveryRoot, command.provider, command.session, previous => {
|
|
1478
|
+
const scopes = new Set(Array.isArray(previous?.listPinScopes) ? previous.listPinScopes : previous?.listPinned ? ['legacy'] : []);
|
|
1479
|
+
if (command.enabled) scopes.add(pinScope); else scopes.delete(pinScope);
|
|
1480
|
+
return {
|
|
1481
|
+
...(previous || { schemaVersion: 1, provider: command.provider, session: command.session, cwd: candidate.cwd, observedAt: Date.now() }),
|
|
1482
|
+
listPinned: scopes.size > 0, listPinScopes: [...scopes],
|
|
1483
|
+
...(command.enabled ? { listMetadata: { title: candidate.title || '', createdAt: candidate.createdAt ?? null, lastActivityAt: candidate.lastActivityAt ?? null } } : {}),
|
|
1484
|
+
};
|
|
1485
|
+
});
|
|
1486
|
+
refreshSessions(true);
|
|
1427
1487
|
} else if (action === "session_archive" || action === "session_restore") {
|
|
1428
1488
|
const candidate = await selectedSession(command, { preferObserved: true });
|
|
1429
1489
|
await authorizeWork(commandScope);
|