@codedology/code-forge 0.2.2 → 0.2.3

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/CHANGELOG.md CHANGED
@@ -6,6 +6,13 @@ waits on a second real consumer (plan §10.4, Q17).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.2.3] — 2026-10-01
10
+
11
+ ### Fixed
12
+
13
+ - 1Password: code-forge prints a line before each call that may make 1Password ask for approval, and waits 60 s instead
14
+ of 20 s, so a Touch ID or password prompt no longer times out while you look for it.
15
+
9
16
  ## [0.2.2] — 2026-10-01
10
17
 
11
18
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codedology/code-forge",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Plan/harden/code/review orchestration CLI and Agent Skill for cross-model, parallel, evidence-gated feature delivery.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,7 +10,7 @@
10
10
  # copied install with no package next to it); `test/skill/shim.test.mjs` asserts the pin
11
11
  # equals package.json's version.
12
12
  # The shim holds no logic of its own: every verb, flag and message is the CLI's.
13
- PINNED_VERSION="0.2.2"
13
+ PINNED_VERSION="0.2.3"
14
14
  set -eu
15
15
 
16
16
  self="$0"
package/src/cli/keys.mjs CHANGED
@@ -16,7 +16,7 @@
16
16
  */
17
17
 
18
18
  import { writeSafe } from '../util/redact.mjs';
19
- import { describeOpItem, isOpRef, OP_MESSAGES, opItemIdFromInput, toOpRef } from '../keys/onepassword.mjs';
19
+ import { describeOpItem, isOpRef, OP_APPROVE_NOTE, OP_MESSAGES, opItemIdFromInput, toOpRef } from '../keys/onepassword.mjs';
20
20
  import { assertKeyName, createDefaultKeyStore, parseRef, readOpAndCache, resolveKey } from '../keys/store.mjs';
21
21
 
22
22
  const USAGE = 'usage: code-forge keys list | set <name> [--op <item-id|link|op://ref>] | test <name> [--ref <ref>] | remove <name>\n';
@@ -109,6 +109,7 @@ export async function runKeys(args, { store, stdout = process.stdout, stderr = p
109
109
  err(`${name}: --op must be a 1Password item ID, item link or op://vault/item/field reference\n`);
110
110
  return 2;
111
111
  }
112
+ if (flagArg !== undefined && (itemId !== null || fullRef)) err(`${OP_APPROVE_NOTE}\n`);
112
113
  // A 1Password item ID or link becomes a full op:// reference before any store call (B25).
113
114
  if (flagArg !== undefined && itemId !== null) {
114
115
  /** @type {Awaited<ReturnType<typeof toOpRef>>} */
@@ -26,7 +26,7 @@ import { parse as parseYAML } from 'yaml';
26
26
  import { DEFAULT_CONFIG_FILENAME, loadConfigFile } from '../../config/load.mjs';
27
27
  import { refreshFromCliCaches } from '../../config/refresh.mjs';
28
28
  import { validateConfig } from '../../config/validate.mjs';
29
- import { describeOpItem, isOpRef, OP_MESSAGES, toOpRef } from '../../keys/onepassword.mjs';
29
+ import { describeOpItem, isOpRef, OP_APPROVE_NOTE, OP_MESSAGES, opItemIdFromInput, toOpRef } from '../../keys/onepassword.mjs';
30
30
  import { createDefaultKeyStore, resolveKey } from '../../keys/store.mjs';
31
31
  import { exec } from '../../util/exec.mjs';
32
32
  import { redact } from '../../util/redact.mjs';
@@ -261,7 +261,12 @@ export async function runInit(args, deps = {}) {
261
261
  const missing = [];
262
262
  let jevRef = null;
263
263
  let jevSource = 'none';
264
- const resolveOp = (/** @type {string} */ input) => toOpRef(input, deps.opExec ? { exec: deps.opExec } : {});
264
+ const resolveOp = (/** @type {string} */ input) => {
265
+ // printed at once (stderr), not buffered: the approval prompt appears while op waits
266
+ // only when op will really be called: an item ID or a 1Password link (an op:// ref is kept as is)
267
+ if (opItemIdFromInput(String(input ?? '')) !== null) stderr.write(`${OP_APPROVE_NOTE}\n`);
268
+ return toOpRef(input, deps.opExec ? { exec: deps.opExec } : {});
269
+ };
265
270
  /** @param {import('./steps.mjs').JevAnswer} a */
266
271
  const takeAnswer = (a) => {
267
272
  jevRef = a.ref;
@@ -13,7 +13,11 @@
13
13
 
14
14
  import { exec as realExec } from '../util/exec.mjs';
15
15
 
16
- export const OP_TIMEOUT_MS = 20_000;
16
+ // Long enough for a person to see and approve the 1Password prompt (Touch ID or password).
17
+ export const OP_TIMEOUT_MS = 60_000;
18
+
19
+ /** Shown just before a call that may make 1Password ask for approval. */
20
+ export const OP_APPROVE_NOTE = '1Password may ask you to approve access: check the 1Password window (Touch ID or password).';
17
21
 
18
22
  /** The 1Password failure kinds; agent JSON carries the kind. */
19
23
  export const OP_ERROR_KINDS = Object.freeze(['op_missing', 'op_locked', 'op_timeout', 'op_not_found', 'op_bad_output', 'op_no_field', 'op_bad_input', 'op_failed']);