Ctrl K
ComunidadGuías…

lib/clay-workspace-controls.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
var crypto = require('crypto'), path = require('path');
var input = require('./clay-workspace-input');
var z = require('zod');
function hash(value) { return crypto.createHash('sha256').update(JSON.stringify(value)).digest('hex'); }
function attachWorkspaceControls(ctx) {
  var state = ctx.state, receipts = require('./clay-workspace-receipts').attachReceipts(ctx);
  function authorize() {
    var principal = ctx.authorize();
    if (ctx.session._pendingMessageDrainPaused) throw new Error('Canonical Clay is stopped; explicit owner resumption is required.');
    var identity = ctx.sourceIdentity();
    if (state.sourceIdentity !== undefined && state.sourceIdentity !== identity) throw new Error('The source OS identity changed.');
    state.sourceIdentity = identity; return principal;
  }
  function resolve(slug, domain) {
    var principal = authorize(), project = ctx.getProjects().get(slug), status = project && project.getStatus();
    if (!status || status.isMate) throw new Error('Select an owned ordinary project.');
    ctx.authorizeProject(principal, status);
    var service = project.getWorkspaceProductOperations && project.getWorkspaceProductOperations();
    if (!service) throw new Error('Project workspace controls are unavailable.');
    return { project: project, status: status, service: service, principal: principal, identity: service.rootIdentity(principal, domain) };
  }
  function check(target, exact) {
    var live = resolve(target.slug, target.op.domain);
    if (live.project !== target.live.project || live.service !== target.live.service || live.identity !== target.live.identity || path.resolve(live.status.path) !== path.resolve(target.live.status.path)) throw new Error('The selected project, directory or OS identity was replaced.');
    if (exact && (Date.now() - target.created > 300000 || hash(live.service.snapshot(live.principal, target.op)) !== target.revision)) throw new Error('The exact file, repository or terminal revision changed. Inspect again.');
    return live;
  }
  function read(args) {
    args = z.object({ projectSlug: z.string().min(1).max(200), operation: input.readSchema }).strict().parse(args);
    var live = resolve(args.projectSlug, args.operation.domain), result = live.service.read(live.principal, args.operation);
    var again = resolve(args.projectSlug, args.operation.domain);
    if (live.project !== again.project || live.identity !== again.identity) throw new Error('Project access changed during the read.');
    return result;
  }
  function receipt(args) {
    authorize();
    args = z.object({ projectSlug: z.string(), domain: input.domain, requestId: z.string() }).strict().parse(args);
    resolve(args.projectSlug, args.domain);
    var record = receipts.read(args.requestId);
    if (!record || record.targetKey !== hash([args.projectSlug, args.domain])) throw new Error('No receipt exists for this selected project and domain.');
    return record;
  }
  function inspect(args) {
    args = z.object({ projectSlug: z.string().min(1).max(200), operation: input.writeSchema }).strict().parse(args);
    if (JSON.stringify(args).length > 1400) throw new Error('The complete exact change must fit 1400 characters in the existing owner review.');
    var live = resolve(args.projectSlug, args.operation.domain), snapshot = live.service.snapshot(live.principal, args.operation);
    var token = 'workspace-control:' + crypto.randomUUID();
    if (state.targets.size >= 100) state.targets.delete(state.targets.keys().next().value);
    var target = { slug: args.projectSlug, op: args.operation, live: live, snapshot: snapshot, revision: hash(snapshot), created: Date.now() };
    target.presentationValid = function () { check(target, true); }; state.targets.set(token, target);
    return { targetToken: token, projectSlug: args.projectSlug, operation: args.operation, expiresInSeconds: 300 };
  }
  function act(args) {
    authorize();
    args = z.object({ targetToken: z.string(), requestId: z.string().max(128), why: z.string().trim().min(1).max(300) }).strict().parse(args);
    var target = state.targets.get(args.targetToken);
    if (!target) throw new Error('Inspect the exact project workspace change first.');
    var key = hash([target.slug, target.live.identity, target.op, args.why]), previous = state.requests.get(args.requestId), durable = receipts.read(args.requestId, key);
    if (previous) { if (previous.key !== key) throw new Error('requestId names another intent.'); return previous.promise.then(function (result) { check(target, false); return result; }); }
    if (durable) { check(target, false); return durable.status === 'applying' ? { status: 'failed', persisted: 'unknown', retrySafe: false, error: 'The saved attempt is interrupted or uncertain. Inspect its effects; it will never replay automatically.' } : durable.result; }
    if (state.requests.size >= 100) throw new Error('Too many workspace requests in this query.');
    var promise = Promise.resolve().then(async function () {
      check(target, true);
      var question = 'Apply this exact selected-project workspace change:\n' + JSON.stringify({ projectSlug: target.slug, operation: target.op }) + '\nWhy: ' + args.why;
      if (target.op.domain === 'terminal' && target.op.id) question += '\nExact terminal: ' + target.snapshot.title + ' (' + target.snapshot.identity + ')';
      if (question.length > 2000) throw new Error('The exact change does not fit the owner review.');
      var answer = await ctx.review(question, function () { check(target, true); });
      if (answer.status !== 'submitted' || !answer.answers.control || answer.answers.control.length !== 1 || answer.answers.control[0] !== 'Apply exact change') return { status: 'cancelled' };
      var live = check(target, true);
      receipts.save({ id: args.requestId, key: key, targetKey: hash([target.slug, target.op.domain]), status: 'applying' });
      live = check(target, true);
      var result;
      try {
        result = Object.assign({ status: 'completed', domain: target.op.domain, action: target.op.action }, await live.service.apply(live.principal, target.op, target.snapshot, function () { check(target, false); }));
      } catch (error) { result = Object.assign({ status: 'failed', domain: target.op.domain, action: target.op.action, error: error.message, retrySafe: false }, error.productControlResult || {}); }
      try { receipts.save({ id: args.requestId, key: key, targetKey: hash([target.slug, target.op.domain]), status: 'finished', result: result }); }
      catch (error) { return Object.assign({}, result, { status: 'failed', receiptSaved: false, retrySafe: false, error: 'The target outcome could not be retained in the source receipt. ' + error.message }); }
      return result;
    }).catch(function (error) { return Object.assign({ status: 'failed', retrySafe: false, error: error.message }, error.productControlResult || {}); });
    state.requests.set(args.requestId, { key: key, promise: promise }); return promise;
  }
  return { readWorkspaceControl: read, readWorkspaceReceipt: receipt, inspectWorkspaceChange: inspect, actWorkspace: act };
}
module.exports = { attachWorkspaceControls: attachWorkspaceControls };