File size: 4,355 Bytes
a00031a
 
 
dfcb66f
a00031a
dfcb66f
a00031a
 
 
 
 
 
 
dfcb66f
 
a00031a
 
 
dfcb66f
a00031a
dfcb66f
 
a00031a
dfcb66f
 
 
 
 
 
 
a00031a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dfcb66f
a00031a
 
 
 
 
 
 
 
 
 
 
 
 
dfcb66f
a00031a
 
 
 
 
dfcb66f
 
 
a00031a
 
 
 
 
dfcb66f
a00031a
 
 
 
dfcb66f
a00031a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dfcb66f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import { mkdir, readFile, writeFile } from 'node:fs/promises';
import { dirname, join } from 'node:path';
import { homedir } from 'node:os';

const DEFAULT_STATE_PATH = join(homedir(), '.config', 'sin', 'sin-code-integration', 'onboarding-state.json');

type OnboardingState = {
  ownerEmail?: string;
  notes?: string;
  updatedAt?: string;
};

export type TemplateAgentAction =
  | { action: 'agent.help' }
  | { action: 'sin.code.integration.health' }
  | { action: 'sin.code.integration.room13.claim'; room13Url?: string; bearerToken?: string; workerName?: string; confirm?: boolean }
  | { action: 'sin.code.integration.onboarding.status' }
  | { action: 'sin.code.integration.onboarding.save'; ownerEmail?: string; notes?: string; confirm?: boolean };

export async function executeTemplateAgentAction(action: TemplateAgentAction): Promise<unknown> {
  switch (action.action) {
    case 'agent.help':
      return buildHelpPayload();
    case 'sin.code.integration.health':
      return {
        ok: true,
        agent: 'sin-code-integration',
        primaryModel: 'openai/gpt-5.4',
        team: 'Team - Coding',
      };
    case 'sin.code.integration.room13.claim':
      return await runRoom13Claim(action);
    case 'sin.code.integration.onboarding.status':
      return {
        ok: true,
        statePath: DEFAULT_STATE_PATH,
        state: await readState(),
      };
    case 'sin.code.integration.onboarding.save':
      if (!action.confirm) {
        throw new Error('input_required:confirm=true required');
      }
      return {
        ok: true,
        statePath: DEFAULT_STATE_PATH,
        state: await writeState({
          ownerEmail: clean(action.ownerEmail),
          notes: clean(action.notes),
          updatedAt: new Date().toISOString(),
        }),
      };
  }
}

function buildHelpPayload() {
  return {
    ok: true,
    agent: 'sin-code-integration',
    actions: ['sin.code.integration.health', 'sin.code.integration.room13.claim', 'sin.code.integration.onboarding.status', 'sin.code.integration.onboarding.save'],
    controlPlane: {
      projectionMode: 'control-plane-first',
      capabilityRegistry: 'control_plane.capabilities',
      consumerAuthScript: './scripts/hf_pull_script.py',
      completeInstallScript: './scripts/complete-install.sh',
    },
  };
}

async function readState(): Promise<OnboardingState | null> {
  try {
    return JSON.parse(await readFile(DEFAULT_STATE_PATH, 'utf8')) as OnboardingState;
  } catch {
    return null;
  }
}

async function writeState(state: OnboardingState) {
  await mkdir(dirname(DEFAULT_STATE_PATH), { recursive: true });
  await writeFile(DEFAULT_STATE_PATH, `${JSON.stringify(state, null, 2)}\n`, 'utf8');
  return state;
}

function clean(value: string | undefined) {
  const normalized = String(value || '').trim();
  return normalized || undefined;
}

async function runRoom13Claim(action: any) {
  const url = action.room13Url || process.env.ROOM13_URL;
  const token = action.bearerToken || process.env.ROOM13_BEARER_TOKEN;
  const worker = action.workerName || process.env.ROOM13_WORKER_NAME || 'sin-code-integration';
  if (!url || !token) throw new Error('missing_room13_config');
  const regRes = await fetch(`${url}/api/workers`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
    body: JSON.stringify({ name: `${worker}:team-coding`, type: 'general', capabilities: ['zeus_github_branch', 'sin_issues_pool_issue'], worker_identity: worker, persona_id: worker }),
  });
  if (!regRes.ok) throw new Error(`Failed to register worker: ${await regRes.text()}`);
  const workerId = (await regRes.json() as any).id;
  const claimRes = await fetch(`${url}/api/tasks/claim-next`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
    body: JSON.stringify({ worker_id: workerId, accepted_types: ['zeus_github_branch', 'sin_issues_pool_issue'], accepted_team_ids: ['team-coding'], min_priority: 'low', run_id: `${worker}-${Date.now()}`, lease_epoch: 0 }),
  });
  if (claimRes.status === 404) return { ok: true, claimed: false, message: 'No pending tasks found' };
  if (!claimRes.ok) throw new Error(`Failed to claim task: ${await claimRes.text()}`);
  return { ok: true, claimed: true, workerId, task: await claimRes.json() };
}