@capybara-hq/kernel 0.1.0-rc.27 → 0.1.0-rc.28

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.
Files changed (88) hide show
  1. package/dist/app.js +2 -0
  2. package/dist/catalog/catalog-content.d.ts +15 -3
  3. package/dist/catalog/catalog-content.js +5 -3
  4. package/dist/catalog/catalog-scope.service.js +3 -2
  5. package/dist/catalog/marketplaces.service.d.ts +1 -1
  6. package/dist/catalog/org-catalog.service.js +10 -3
  7. package/dist/catalog/plugin-install.d.ts +34 -18
  8. package/dist/catalog/plugin-install.js +84 -46
  9. package/dist/catalog/plugin-upgrade.js +1 -0
  10. package/dist/channels/actions.d.ts +4 -1
  11. package/dist/channels/actions.js +5 -2
  12. package/dist/channels/cards.d.ts +7 -1
  13. package/dist/channels/cards.js +28 -1
  14. package/dist/channels/phrases.d.ts +15 -0
  15. package/dist/channels/phrases.js +9 -0
  16. package/dist/config/schema.d.ts +8 -0
  17. package/dist/config/schema.js +69 -0
  18. package/dist/conversations/events.d.ts +14 -0
  19. package/dist/conversations/events.js +20 -0
  20. package/dist/db/kernel-schema.d.ts +19 -4
  21. package/dist/errors.d.ts +5 -0
  22. package/dist/errors.js +5 -0
  23. package/dist/git/gateway.d.ts +93 -0
  24. package/dist/git/gateway.js +750 -0
  25. package/dist/git/gateway.route.d.ts +16 -0
  26. package/dist/git/gateway.route.js +41 -0
  27. package/dist/git/git.module.d.ts +10 -0
  28. package/dist/git/git.module.js +31 -0
  29. package/dist/git/identity.d.ts +80 -0
  30. package/dist/git/identity.js +209 -0
  31. package/dist/git/pkt-line.d.ts +53 -0
  32. package/dist/git/pkt-line.js +146 -0
  33. package/dist/git/run-end.d.ts +29 -0
  34. package/dist/git/run-end.js +121 -0
  35. package/dist/git/sources.d.ts +42 -0
  36. package/dist/git/sources.js +134 -0
  37. package/dist/git/tickets.d.ts +69 -0
  38. package/dist/git/tickets.js +194 -0
  39. package/dist/http/api.module.js +3 -0
  40. package/dist/http/app.d.ts +6 -0
  41. package/dist/http/app.js +3 -0
  42. package/dist/infra/config/kernel-config.service.js +2 -0
  43. package/dist/orgs/settings.service.d.ts +21 -0
  44. package/dist/orgs/settings.service.js +18 -0
  45. package/dist/overrides.d.ts +6 -0
  46. package/dist/overrides.js +4 -0
  47. package/dist/platform/exclusions.js +3 -0
  48. package/dist/runtime/run-finish.d.ts +5 -0
  49. package/dist/runtime/run-finish.js +12 -3
  50. package/dist/runtime/runtime.module.js +2 -0
  51. package/dist/runtime/waits.js +7 -5
  52. package/dist/schedules/fire.d.ts +3 -3
  53. package/dist/schedules/fire.js +7 -4
  54. package/dist/schedules/grant-rules.d.ts +40 -0
  55. package/dist/schedules/grant-rules.js +83 -0
  56. package/dist/schedules/scheduled-tasks.service.d.ts +9 -7
  57. package/dist/schedules/scheduled-tasks.service.js +50 -15
  58. package/dist/schedules/types.d.ts +2 -0
  59. package/dist/tools/approvals.service.d.ts +100 -19
  60. package/dist/tools/approvals.service.js +288 -21
  61. package/dist/tools/builtin-names.d.ts +4 -2
  62. package/dist/tools/builtin-names.js +6 -1
  63. package/dist/tools/builtins/schedules.d.ts +11 -9
  64. package/dist/tools/builtins/schedules.js +202 -44
  65. package/dist/tools/connector-account-policies.d.ts +8 -0
  66. package/dist/tools/connector-account-policies.js +8 -0
  67. package/dist/tools/connectors.controller.d.ts +2 -0
  68. package/dist/tools/connectors.controller.js +5 -1
  69. package/dist/tools/connectors.service.d.ts +46 -3
  70. package/dist/tools/connectors.service.js +98 -5
  71. package/dist/tools/credentials.d.ts +18 -0
  72. package/dist/tools/credentials.js +60 -0
  73. package/dist/tools/credentials.module.d.ts +7 -0
  74. package/dist/tools/credentials.module.js +22 -0
  75. package/dist/tools/git-asks.d.ts +113 -0
  76. package/dist/tools/git-asks.js +174 -0
  77. package/dist/tools/git-push-policy.d.ts +89 -0
  78. package/dist/tools/git-push-policy.js +175 -0
  79. package/dist/tools/info.d.ts +3 -3
  80. package/dist/tools/info.js +3 -3
  81. package/dist/tools/network-asks.d.ts +5 -0
  82. package/dist/tools/network-asks.js +9 -2
  83. package/dist/tools/tools.module.js +4 -3
  84. package/package.json +3 -3
  85. package/src/migrations/0126_git_gateway.sql +10 -0
  86. package/src/migrations/0127_git_push_policy.sql +12 -0
  87. package/src/migrations/0128_scheduled_task_plugin_disabled.sql +10 -0
  88. package/src/migrations/0129_connector_plugin_disabled.sql +5 -0
@@ -14,6 +14,7 @@ import { AgentLookup } from "../agents/agent-lookup.js";
14
14
  import { ConversationAccess } from "../conversations/access.js";
15
15
  import { readMessageContext } from "../conversations/message-context.js";
16
16
  import { ApiError } from "../errors.js";
17
+ import { enabledExtensionsByOrg, isExtensionEnabled } from "../extensions/enabled.js";
17
18
  import { ExtensionRegistry } from "../extensions/registry.js";
18
19
  import { audit } from "../identity/audit.js";
19
20
  import { KernelConfigService } from "../infra/config/kernel-config.service.js";
@@ -33,7 +34,7 @@ import { ToolRegistry } from "../tools/registry.js";
33
34
  import { assembleCalendar, CALENDAR_LIMITS, CALENDAR_RANGE_DAYS, CALENDAR_TASK_RANGE_DAYS, calendarRunReadLimit, } from "./calendar.js";
34
35
  import { readScheduleSettings } from "./effective-settings.js";
35
36
  import { grantNotAllowed, scheduleDisabled, scheduleForbidden, scheduleNotFound, targetInvalid, } from "./errors.js";
36
- import { grantRefusal, grantRefusalOf, isNetworkGrantKey, isPolicyGrantKey, isTierGrantKey, NETWORK_GRANT_PREFIX, NETWORK_GRANT_SPEC_HASH, networkGrantHost, networkGrantRefusal, TIER_GRANT_SPEC_HASH, tierGrantRefusal, } from "./grant-rules.js";
37
+ import { GIT_GRANT_SPEC_HASH, GIT_PUSH_GRANT, gitGrantRefusal, grantRefusal, grantRefusalOf, isGitGrantKey, isNetworkGrantKey, isPolicyGrantKey, isTierGrantKey, NETWORK_GRANT_PREFIX, NETWORK_GRANT_SPEC_HASH, networkGrantHost, networkGrantRefusal, normalizeGitGrantKey, TIER_GRANT_SPEC_HASH, tierGrantRefusal, } from "./grant-rules.js";
37
38
  import { oweSchedFire, oweSchedSettleUnfired } from "./job-ids.js";
38
39
  import { pauseTaskIn } from "./pause.js";
39
40
  import { jitterForGap, minGapMinutes, nextTick, validateTrigger } from "./schedule-math.js";
@@ -41,8 +42,15 @@ import { ScheduledTaskStore } from "./store.js";
41
42
  export { grantRefusal, grantRefusalOf, networkGrantRefusal, };
42
43
  /** The refusal of a network grant written outside a person's web session. */
43
44
  const NETWORK_GRANT_NEEDS_PERSON = "Network domains are approved on the task page by a person.";
45
+ /** Why a git push grant needs a person (sandbox git credentials spec §7). */
46
+ const GIT_GRANT_NEEDS_PERSON = "Git pushes are approved on the task page by a person.";
44
47
  /** The refusal of a sandbox tier grant written outside a person's web session. */
45
48
  const TIER_GRANT_NEEDS_PERSON = "A sandbox level is approved on the task page by a person.";
49
+ /**
50
+ * A grant that belongs to no tool: a network domain, a git push or a sandbox tier (never stale,
51
+ * never re-resolved).
52
+ */
53
+ const isNonToolGrantKey = (key) => isPolicyGrantKey(key) || isGitGrantKey(key);
46
54
  const RUNS_DEFAULT = 50;
47
55
  const RUNS_MAX = 200;
48
56
  const DAY_MS = 86_400_000;
@@ -194,8 +202,8 @@ let ScheduledTasksService = class ScheduledTasksService {
194
202
  changes.agentId = agent.id;
195
203
  // the grants were approved for the old agent's tools: each must hold for the new agent
196
204
  // too (refused, so the creator sees which), and takes the new agent's definition; network
197
- // and sandbox tier grants belong to no tool and stay as they are
198
- const held = (await this.store.listGrants(t, task.id)).filter((g) => !isPolicyGrantKey(g.toolKey));
205
+ // and git and sandbox tier grants belong to no tool and stay as they are
206
+ const held = (await this.store.listGrants(t, task.id)).filter((g) => !isNonToolGrantKey(g.toolKey));
199
207
  const regranted = await this.resolveGrants(orgId, role, agent, settings, held.map((g) => ({
200
208
  toolKey: g.toolKey,
201
209
  ...(g.connectorId !== null && { connectorId: g.connectorId }),
@@ -465,15 +473,18 @@ let ScheduledTasksService = class ScheduledTasksService {
465
473
  });
466
474
  }
467
475
  /**
468
- * The chats the caller can point a `chat` task at (spec §8): per active connection of the org,
469
- * their DM threads (archived included) and, on a channel with threads, the groups they have a
470
- * thread in. Members up (`schedules.use`, the route's).
476
+ * The chats the caller can point a `chat` task at (spec §8): per active connection of the org
477
+ * whose extension is enabled in it, their DM threads (archived included) and, on a channel with
478
+ * threads, the groups they have a thread in. Members up (`schedules.use`, the route's).
471
479
  */
472
480
  async chatTargets(orgId, accountId) {
473
481
  await this.liveRole(orgId, accountId);
474
482
  const rows = await this.db.db
475
483
  .selectFrom("channel_threads")
476
484
  .innerJoin("channel_connections", "channel_connections.id", "channel_threads.connection_id")
485
+ .innerJoin(enabledExtensionsByOrg(this.db.db).as("en"), (j) => j
486
+ .onRef("en.org_id", "=", "channel_connections.org_id")
487
+ .onRef("en.plugin", "=", "channel_connections.plugin"))
477
488
  .select([
478
489
  "channel_connections.id as connection_id",
479
490
  "channel_connections.name",
@@ -556,13 +567,13 @@ let ScheduledTasksService = class ScheduledTasksService {
556
567
  return [];
557
568
  // the creator's view of the agent's tools: a grant whose tool changed or left is stale;
558
569
  // unknown (null) when the tools cannot be read now, rather than failing the task page
559
- const current = grants.every((g) => isPolicyGrantKey(g.toolKey))
570
+ const current = grants.every((g) => isNonToolGrantKey(g.toolKey))
560
571
  ? new Map()
561
572
  : await this.agentToolFacts(orgId, task.accountId, task.agentId);
562
573
  return grants.map((g) => ({
563
574
  ...g,
564
- // a network or sandbox tier grant names no tool definition: never stale
565
- stale: isPolicyGrantKey(g.toolKey)
575
+ // a network, git or sandbox tier grant names no tool definition: never stale
576
+ stale: isNonToolGrantKey(g.toolKey)
566
577
  ? false
567
578
  : current === null
568
579
  ? null
@@ -716,8 +727,9 @@ let ScheduledTasksService = class ScheduledTasksService {
716
727
  // a refused tool granted since drops out, unless its grant no longer matches the tool's
717
728
  // definition (stale: it would be refused again); a refused domain granted since drops out
718
729
  // while the org's network allowlist admits it (network ask-to-allow spec §8.3)
730
+ // a refused git push drops out once the task holds a grant for it or for every repository;
719
731
  // a refused sandbox level granted since drops out while the org's ceiling is still open
720
- const isTool = (k) => !k.startsWith("connection:") && !isPolicyGrantKey(k);
732
+ const isTool = (k) => !k.startsWith("connection:") && !isNonToolGrantKey(k);
721
733
  const facts = refused.some(isTool) ? await toolsOf(task.agentId) : null;
722
734
  const limits = refused.some(isNetworkGrantKey) ? await orgLimits() : null;
723
735
  const open = refused.some(isTierGrantKey) ? await openReachable() : false;
@@ -726,6 +738,8 @@ let ScheduledTasksService = class ScheduledTasksService {
726
738
  const hash = have?.get(k);
727
739
  if (isPolicyGrantKey(k))
728
740
  return hash === undefined || !admits(k);
741
+ if (isGitGrantKey(k))
742
+ return hash === undefined && have?.get(GIT_PUSH_GRANT) === undefined;
729
743
  if (hash === undefined)
730
744
  return true;
731
745
  const current = facts?.get(k);
@@ -905,9 +919,9 @@ let ScheduledTasksService = class ScheduledTasksService {
905
919
  * - the mode and its fields agree (`conversation`: a conversation and no chat; `chat`: a chat
906
920
  * and no conversation; `new`: neither);
907
921
  * - `conversation`: the creator's live chat conversation with this agent, still accessible;
908
- * - `chat`: the connection is active and bound to this agent; a DM needs a thread row (archived
909
- * allowed) of the creator in that chat; a group needs the creator's thread row in the group
910
- * and a channel with threads.
922
+ * - `chat`: the connection is active, its channel extension is enabled in this org, and it is
923
+ * bound to this agent; a DM needs a thread row (archived allowed) of the creator in that chat;
924
+ * a group needs the creator's thread row in the group and a channel with threads.
911
925
  */
912
926
  async checkTarget(orgId, accountId, agentId, target) {
913
927
  const { mode, conversationId, chat } = target;
@@ -947,6 +961,9 @@ let ScheduledTasksService = class ScheduledTasksService {
947
961
  if (conn?.status !== "active") {
948
962
  throw targetInvalid("The channel connection does not exist or is not active");
949
963
  }
964
+ if (!(await isExtensionEnabled(t, orgId, conn.plugin))) {
965
+ throw targetInvalid("The channel's extension is disabled in this organization, so its chats cannot receive a task's runs");
966
+ }
950
967
  if (conn.agent_id !== agentId) {
951
968
  throw targetInvalid("The chat belongs to another agent: use the connection's agent");
952
969
  }
@@ -1029,7 +1046,9 @@ let ScheduledTasksService = class ScheduledTasksService {
1029
1046
  * `deviceId`, the task's device (null: none can be determined, the device rule is skipped),
1030
1047
  * stored with `spec_hash` `network` and no connector (plan P-D7), and only when
1031
1048
  * `source.fromSession` (a person on the task page; never a token, the Platform tool or the
1032
- * schedule tools). Duplicates keep the last.
1049
+ * schedule tools). Each git push key (`git:push`, `git:push:<owner>/<repo>`, the repository
1050
+ * lower-cased) is refused by {@link gitGrantRefusal} and stored with `spec_hash` `git` and no
1051
+ * connector, also only when `source.fromSession`. Duplicates keep the last.
1033
1052
  */
1034
1053
  async resolveGrants(orgId, role, agent, settings, grants, deviceId, source = {}) {
1035
1054
  if (grants.length === 0)
@@ -1052,6 +1071,22 @@ let ScheduledTasksService = class ScheduledTasksService {
1052
1071
  out.set(toolKey, { toolKey, specHash: NETWORK_GRANT_SPEC_HASH, connectorId: null });
1053
1072
  }
1054
1073
  }
1074
+ const git = grants.filter((g) => isGitGrantKey(g.toolKey));
1075
+ if (git.length > 0) {
1076
+ // a push is the creator's decision, never an agent's or a token's (as network domains)
1077
+ if (source.fromSession !== true)
1078
+ throw grantNotAllowed(GIT_GRANT_NEEDS_PERSON);
1079
+ for (const g of git) {
1080
+ if (g.connectorId !== undefined) {
1081
+ throw grantNotAllowed(`${g.toolKey} is a git push and comes from no connector`);
1082
+ }
1083
+ const toolKey = normalizeGitGrantKey(g.toolKey);
1084
+ const why = gitGrantRefusal(toolKey, { forbiddenTools: settings.forbiddenTools });
1085
+ if (why !== null)
1086
+ throw grantNotAllowed(why.message);
1087
+ out.set(toolKey, { toolKey, specHash: GIT_GRANT_SPEC_HASH, connectorId: null });
1088
+ }
1089
+ }
1055
1090
  const tiers = grants.filter((g) => isTierGrantKey(g.toolKey));
1056
1091
  if (tiers.length > 0) {
1057
1092
  if (source.fromSession !== true)
@@ -1076,7 +1111,7 @@ let ScheduledTasksService = class ScheduledTasksService {
1076
1111
  });
1077
1112
  }
1078
1113
  }
1079
- const toolGrants = grants.filter((g) => !isPolicyGrantKey(g.toolKey));
1114
+ const toolGrants = grants.filter((g) => !isNonToolGrantKey(g.toolKey));
1080
1115
  if (toolGrants.length === 0)
1081
1116
  return [...out.values()];
1082
1117
  const d = agent.definition;
@@ -28,6 +28,8 @@ export type SchedulePauseReason = "creator" | "admin" | "failures" | "creator_in
28
28
  | "invalid_schedule";
29
29
  export type TaskRunStatus = "pending" | "running" | "completed" | "failed" | "skipped";
30
30
  export type TaskRunSkipReason = "missed" | "overlap" | "rate_limited" | "queue_paused" | "removed" | "device_offline" | "creator_inactive" | "agent_gone" | "target_gone" | "conversation_gone" | "org_disabled"
31
+ /** The channel's extension is disabled in the org: the task stays active. */
32
+ | "plugin_disabled"
31
33
  /** A group chat on a channel without threads (a group run needs its own thread). */
32
34
  | "unsupported_target"
33
35
  /** The task was deleted after the run was recorded. */
@@ -18,8 +18,23 @@ export { APPROVAL_DENY_REASON_MAX_CHARS } from "../conversations/events.js";
18
18
  export declare const APPROVALS_LIST_MAX = 100;
19
19
  export type ApprovalStatus = "pending" | "approved" | "denied" | "expired" | "cancelled" | "skipped";
20
20
  export type ApprovalScope = "once" | "session" | "always";
21
- /** What an approval asks: a tool call, or the device owner about refused network hosts. */
22
- export type ApprovalKind = "tool" | "network";
21
+ /**
22
+ * What an approval asks: a tool call, the device owner about refused network hosts, or the actor
23
+ * about a git push the gateway held.
24
+ */
25
+ export type ApprovalKind = "tool" | "network" | "git";
26
+ /**
27
+ * The formatted `tool_result` of a command an ask kept (≤ 16 KB; larger output already archived),
28
+ * and the display-only fields the pipeline writes with it when the ask settles.
29
+ */
30
+ export interface KeptToolResult {
31
+ content: string;
32
+ isError: boolean;
33
+ outputId?: string;
34
+ contentTypes?: string[];
35
+ display?: ToolDisplay;
36
+ view?: ToolView;
37
+ }
23
38
  /**
24
39
  * A network ask's `detail` (network ask-to-allow spec §6.1, P-D2): the device, the refused hosts,
25
40
  * the command and its kept `tool_result` (written with a note when the ask settles; the command is
@@ -33,18 +48,8 @@ export interface NetworkAskDetail {
33
48
  }[];
34
49
  command: string;
35
50
  description: string | null;
36
- /**
37
- * The formatted `tool_result` of the command (≤ 16 KB; larger output already archived), and the
38
- * display-only fields the pipeline writes with it when the ask settles.
39
- */
40
- result: {
41
- content: string;
42
- isError: boolean;
43
- outputId?: string;
44
- contentTypes?: string[];
45
- display?: ToolDisplay;
46
- view?: ToolView;
47
- };
51
+ /** The formatted `tool_result` of the command and its display-only fields. */
52
+ result: KeptToolResult;
48
53
  /** The hosts the decision allowed (every approved decision writes them; none: nothing). */
49
54
  grantedHosts?: string[];
50
55
  /**
@@ -74,11 +79,32 @@ export interface NetworkAskAttempt {
74
79
  }
75
80
  /** A network ask's detail as the API shows it: without the kept command result. */
76
81
  export type NetworkAskView = Omit<NetworkAskDetail, "result">;
82
+ /**
83
+ * A git push ask's `detail` (sandbox git credentials spec §7): the host, the repository
84
+ * (`<owner>/<repo>`, normalized) and the refs of the push the gateway held, the command that ran
85
+ * it and its device, the kept `tool_result` (written with a note when the ask settles; the push is
86
+ * never run again by the kernel), and once approved what took effect. The connector whose
87
+ * credential the push used is the approval's `connectorId`.
88
+ */
89
+ export interface GitAskDetail {
90
+ host: string;
91
+ repo: string;
92
+ refs: string[];
93
+ command?: string;
94
+ deviceId?: string;
95
+ result: KeptToolResult;
96
+ /** What took effect: a run grant (`once`) or the member's standing allow for the repo (`always`). */
97
+ outcome?: "once" | "always";
98
+ }
99
+ /** A git ask's detail as the API shows it: without the kept command result. */
100
+ export type GitAskView = Omit<GitAskDetail, "result">;
77
101
  /**
78
102
  * The model-visible note written after a network ask's kept result when its run is stopped before
79
103
  * the device owner answered (spec §6.7).
80
104
  */
81
105
  export declare const NETWORK_ASK_CANCELLED_NOTE = "[network] The run was stopped before the user answered; access stays blocked.";
106
+ /** The model-visible note after a git ask's kept result when its run is stopped before the answer. */
107
+ export declare const GIT_ASK_CANCELLED_NOTE = "[git] The run was stopped before the user answered; the push was not made.";
82
108
  /** 一条审批记录。 */
83
109
  export interface ApprovalRecord {
84
110
  id: string;
@@ -90,8 +116,10 @@ export interface ApprovalRecord {
90
116
  attempt: number;
91
117
  /** `network`: a network ask (its tool key is `Bash`, its facts in {@link detail}). */
92
118
  kind: ApprovalKind;
93
- /** A network ask's hosts, command, kept result and outcome; null for a tool approval. */
119
+ /** A network ask's hosts, command, kept result and outcome; null for any other kind. */
94
120
  detail: NetworkAskDetail | null;
121
+ /** A git ask's host, repository, refs, kept result and outcome; null for any other kind. */
122
+ git: GitAskDetail | null;
95
123
  toolKey: string;
96
124
  specHash: string;
97
125
  connectorId: string | null;
@@ -117,11 +145,12 @@ export interface ApprovalRecord {
117
145
  expiresAt: string;
118
146
  createdAt: string;
119
147
  }
120
- /** An approval as a route answers it: a network ask's detail without the kept command result. */
121
- export interface ApprovalPublicRecord extends Omit<ApprovalRecord, "detail"> {
148
+ /** An approval as a route answers it: a network or git ask's detail without the kept command result. */
149
+ export interface ApprovalPublicRecord extends Omit<ApprovalRecord, "detail" | "git"> {
122
150
  detail: NetworkAskView | null;
151
+ git: GitAskView | null;
123
152
  }
124
- /** The record without a network ask's kept command result (what routes and cards may show). */
153
+ /** The record without an ask's kept command result (what routes and cards may show). */
125
154
  export declare function publicRecord(r: ApprovalRecord): ApprovalPublicRecord;
126
155
  /** 审批详情(列表与详情接口返回)。 */
127
156
  export interface ApprovalView extends ApprovalPublicRecord {
@@ -210,6 +239,22 @@ export interface NetworkAskInput {
210
239
  }
211
240
  /** The tool key a network ask is recorded under (the command ran in `Bash`). */
212
241
  export declare const NETWORK_ASK_TOOL_KEY = "Bash";
242
+ /** The tool key a git ask is recorded under (the push ran in a `Bash` command). */
243
+ export declare const GIT_ASK_TOOL_KEY = "Bash";
244
+ /** A new git push ask (sandbox git credentials spec §7), made by the tool pipeline. */
245
+ export interface GitAskInput {
246
+ orgId: string;
247
+ conversationId: string;
248
+ runId: string;
249
+ /** The call's step (written to `approval_requested`). */
250
+ step: number;
251
+ callId: string;
252
+ /** The actor whose credential the push used: the only person who may decide. */
253
+ requestedFor: string;
254
+ /** The connector whose credential the push used (its git source). */
255
+ connectorId: string;
256
+ detail: Omit<GitAskDetail, "outcome">;
257
+ }
213
258
  /** 「以后都允许」授权(本人可撤销)。 */
214
259
  export interface ToolGrantView {
215
260
  agentId: string;
@@ -278,6 +323,17 @@ export declare class ApprovalsService {
278
323
  */
279
324
  requestNetwork(input: NetworkAskInput): Promise<ApprovalRecord>;
280
325
  private requestNetworkIn;
326
+ /**
327
+ * A git push ask (sandbox git credentials spec §7): a pending approval of kind `git` for the
328
+ * actor whose credential the push used, expiring like a tool approval, and its
329
+ * `approval_requested` (tool key `Bash`, the display-only `git` field), in one transaction. The
330
+ * scopes are `once` (a run grant) and, for a personal connector (the push used the actor's own
331
+ * connection), `always` (the actor's standing allow for the repository); an org connector's push
332
+ * acts as the org, so no member allow applies to it. Takes the attempt after the call's other
333
+ * approvals; one per call: a second request returns the first.
334
+ */
335
+ requestGit(input: GitAskInput): Promise<ApprovalRecord>;
336
+ private requestGitIn;
281
337
  /** 当前用户能处理的审批(新的在前,最多 {@link APPROVALS_LIST_MAX} 条);`status` 缺省为全部。 */
282
338
  list(orgId: string, accountId: string, status?: ApprovalStatus): Promise<ApprovalView[]>;
283
339
  /** 详情;当前用户不能处理的一律 `approval.not_found`(不泄露存在)。 */
@@ -302,6 +358,15 @@ export declare class ApprovalsService {
302
358
  * (`late`) and answered with a 409 that says so.
303
359
  */
304
360
  private decideNetwork;
361
+ /**
362
+ * A git push ask's decision (sandbox git credentials spec §7): only the asked actor
363
+ * (`requested_for`) decides, in a signed-in session (a personal access token is refused, as for
364
+ * network asks); `once` is a run grant (the row itself), `always` also writes the actor's
365
+ * standing allow for the repository on that host (`connector_tool_account_policies`,
366
+ * `git_push:<host>/<owner>/<repo>`) in the decision's transaction. The run resumes after the
367
+ * commit.
368
+ */
369
+ private decideGit;
305
370
  /**
306
371
  * 「这台设备一直允许」 (transactional outbox spec §7): the intent of the device change (naming the
307
372
  * ask) is recorded, the `policy` op sent (no transaction open), then {@link settleNetworkOp}
@@ -390,6 +455,19 @@ export declare class ApprovalsService {
390
455
  * decided or one asked of someone else. In the decision's transaction.
391
456
  */
392
457
  private keepTrialNetworkGrant;
458
+ /**
459
+ * The actor's standing allow for pushes to `repo` through the connector (sandbox git
460
+ * credentials spec §7, 「一直允许」): a `connector_tool_account_policies` row named
461
+ * `git_push:<host>/<owner>/<repo>` with policy `allow`, in the decision's transaction.
462
+ */
463
+ private allowRepoIn;
464
+ /**
465
+ * A trial run of a scheduled task (sandbox git credentials spec §7): a push its creator allowed
466
+ * for this run (「这次允许」) becomes the task's `git:push:<owner>/<repo>` grant, when
467
+ * `gitGrantRefusal` allows it (the org does not forbid it). Never for an ask another account
468
+ * decided or one asked of someone else. In the decision's transaction.
469
+ */
470
+ private keepTrialGitGrant;
393
471
  /**
394
472
  * 详情,不做处理人校验(内核内部用:渠道出站投递组装 IM 审批卡片);不存在返回 null。
395
473
  * 不得直接回给请求方——HTTP 接口用 {@link get}。
@@ -399,6 +477,8 @@ export declare class ApprovalsService {
399
477
  forCall(runId: string, callId: string): Promise<ApprovalRecord | null>;
400
478
  /** The network ask of a tool call (at most one per call); null when it has none. */
401
479
  networkForCall(runId: string, callId: string): Promise<ApprovalRecord | null>;
480
+ /** The git push ask of a tool call (at most one per call); null when it has none. */
481
+ gitForCall(runId: string, callId: string): Promise<ApprovalRecord | null>;
402
482
  /**
403
483
  * 超时(等待机制的超时任务调用):仍 pending 且已到期 → 置 expired、写 `approval_decided{expired}`(处理人为 null)。
404
484
  * 与人工决定都锁同一行,恰好一个生效。返回 `expired`(本次生效)/ `not_due`(尚未到期)/
@@ -437,7 +517,8 @@ export declare class ApprovalsService {
437
517
  /**
438
518
  * In the caller's transaction (`mandatory`; it wrote `authorAccountId`'s message in
439
519
  * `conversationId` and holds that conversation's row lock): the message skips the pending
440
- * network asks it closes (network ask-to-allow spec §6.7), as it skips questions: the asks of
520
+ * network and git asks it closes (network ask-to-allow spec §6.7; a git push ask follows the
521
+ * same flow, sandbox git credentials spec §7), as it skips questions: the asks of
441
522
  * active runs `authorAccountId` started, in the conversation and in its sub-agents'
442
523
  * conversations at any depth (their asks are shown in the root). Each becomes `skipped` with
443
524
  * `approval_decided{skipped}` by the author; access stays blocked. Returns the skipped records and