@elinpf/dsh-ops-access-gate 0.1.7 → 0.2.0

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 CHANGED
@@ -27,7 +27,7 @@ The gate sits between the ops-access registry (`@elinpf/dsh-ops-access`) and eve
27
27
  | `defaultTtlMinutes` | `30` | Grant lifetime when `request_access` omits `ttlMinutes` |
28
28
  | `maxTtlMinutes` | `480` | Upper bound for a requested grant lifetime |
29
29
  | `auditFile` | `~/.dsh-ops/audit.log` | JSONL audit log path (`~` expands) |
30
- | `grantTtlOptions` | `[5, 10, 30]` | TTL choices the access panel offers |
30
+ | `grantTtlOptions` | `[10, 30, 60, 120]` | TTL choices the access panel offers |
31
31
  | `pendingRequestTimeoutMinutes` | `5` | How long a parked request awaits a human before auto-rejecting |
32
32
  | `deniedFile` | `~/.dsh-ops/denied.json` | Persisted lockdown state (survives restarts) |
33
33
 
package/README.zh.md CHANGED
@@ -27,7 +27,7 @@ DeepSeek Harness 运维模式的按会话凭据代理(credential brokering)
27
27
  | `defaultTtlMinutes` | `30` | `request_access` 省略 `ttlMinutes` 时的授权时长 |
28
28
  | `maxTtlMinutes` | `480` | 申请授权时长的上限 |
29
29
  | `auditFile` | `~/.dsh-ops/audit.log` | JSONL 审计日志路径(`~` 展开) |
30
- | `grantTtlOptions` | `[5, 10, 30]` | 授权面板提供的 TTL 选项 |
30
+ | `grantTtlOptions` | `[10, 30, 60, 120]` | 授权面板提供的 TTL 选项 |
31
31
  | `pendingRequestTimeoutMinutes` | `5` | 驻留请求等待人工裁决的超时(超时自动拒绝) |
32
32
  | `deniedFile` | `~/.dsh-ops/denied.json` | 持久化封禁状态(重启保留) |
33
33
 
package/lib/index.js CHANGED
@@ -48,7 +48,12 @@ export const Config = z.object({
48
48
  defaultTtlMinutes: z.number().default(30),
49
49
  maxTtlMinutes: z.number().default(480),
50
50
  auditFile: z.string().default('~/.dsh-ops/audit.log'),
51
- grantTtlOptions: z.array(z.number()).default([5, 10, 30]),
51
+ // The panel can only grant one of these options. [5, 10, 30] once made 30
52
+ // the effective ceiling for every grant — agents asked 60/120 for
53
+ // hour-spanning recovery work and were cut to 30 every time, forcing
54
+ // repeat full-approval requests mid-incident (2026-09-10). Include the
55
+ // realistic durations so the human's adjustment is a choice, not a clamp.
56
+ grantTtlOptions: z.array(z.number()).default([10, 30, 60, 120]),
52
57
  pendingRequestTimeoutMinutes: z.number().default(5),
53
58
  deniedFile: z.string().default('~/.dsh-ops/denied.json'),
54
59
  });
@@ -726,7 +731,7 @@ export function apply(ctx, config) {
726
731
  action: { type: 'string', enum: ['request', 'list', 'revoke'], required: true, description: 'request: ask a human for a timed grant; list: show this session\'s active grants; revoke: drop a grant immediately.' },
727
732
  profile: { type: 'string', description: '"kind/name", e.g. "k8s/prod". Required for request and revoke.' },
728
733
  reason: { type: 'string', description: 'Why the access is needed — shown verbatim to the human approver. Required for request.' },
729
- ttlMinutes: { type: 'number', description: 'Requested grant lifetime in minutes (default ' + config.defaultTtlMinutes + ', max ' + config.maxTtlMinutes + '). The human may approve a shorter lifetime from the panel options: ' + config.grantTtlOptions.join(', ') + '.' },
734
+ ttlMinutes: { type: 'number', description: 'Requested grant lifetime in minutes (default ' + config.defaultTtlMinutes + ', max ' + config.maxTtlMinutes + '). Ask for the SMALLEST sufficient lifetime: the human approves one of the fixed panel options (' + config.grantTtlOptions.join(', ') + '), and a request beyond the largest option is almost always cut to it. If the grant lapses mid-work, simply request again.' },
730
735
  },
731
736
  output: {
732
737
  schema: {
@@ -832,7 +837,11 @@ export function apply(ctx, config) {
832
837
  }
833
838
  if (!settled.approved) {
834
839
  const why = settled.outcome === 'timeout'
835
- ? 'no operator decision within ' + config.pendingRequestTimeoutMinutes + ' min'
840
+ // An unanswered request is a SILENT failure for the operator (they
841
+ // may simply not be watching the panel) — tell the agent its next
842
+ // move instead of leaving the work item hanging (2026-09-10: a
843
+ // next-day inspection lost its ssh wing to exactly this).
844
+ ? 'no operator decision within ' + config.pendingRequestTimeoutMinutes + ' min — the request expired. The operator may not be watching the access panel: tell the user a request is waiting (panel: /access-all), then re-request when they are ready'
836
845
  : settled.outcome === 'cancelled'
837
846
  ? 'cancelled'
838
847
  : 'rejected by the operator';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elinpf/dsh-ops-access-gate",
3
- "version": "0.1.7",
3
+ "version": "0.2.0",
4
4
  "description": "Ops access gate — per-session credential brokering. Owns an in-process grant ledger keyed by agent.id and registers a pure-decision broker (ro/rw) into the ops-access seam. Never touches credential fields.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -34,14 +34,14 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@deepseek-ai/schemastery": "^3.18.1",
37
- "@elinpf/dsh-ops-panel": "^0.1.7"
37
+ "@elinpf/dsh-ops-panel": "^0.2.0"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "@deepseek-ai/cordis": "^4.0.1",
41
41
  "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8",
42
42
  "@deepseek-ai/dsh-llm": "^0.1.0-rc.8",
43
43
  "@deepseek-ai/dsh-tools": "^0.1.0-rc.8",
44
- "@elinpf/dsh-ops-access": "^0.1.7"
44
+ "@elinpf/dsh-ops-access": "^0.2.0"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@deepseek-ai/cordis": "4.0.1",
@@ -51,8 +51,8 @@
51
51
  "typescript": "^5.4.0",
52
52
  "vitest": "^4.1.11",
53
53
  "zod": "^4.4.3",
54
- "@elinpf/dsh-ops-access": "0.1.7",
55
- "@elinpf/dsh-ops-panel": "0.1.7"
54
+ "@elinpf/dsh-ops-access": "0.2.0",
55
+ "@elinpf/dsh-ops-panel": "0.2.0"
56
56
  },
57
57
  "license": "MIT",
58
58
  "publishConfig": {