taskchef 3.0.1 → 3.0.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.
Files changed (49) hide show
  1. package/.codex-plugin/plugin.json +1 -1
  2. package/BACKLOG.md +15 -0
  3. package/README.md +28 -7
  4. package/SPEC.md +79 -33
  5. package/index.js +18 -0
  6. package/node_modules/graceful-fs/LICENSE +15 -0
  7. package/node_modules/graceful-fs/README.md +143 -0
  8. package/node_modules/graceful-fs/clone.js +23 -0
  9. package/node_modules/graceful-fs/graceful-fs.js +448 -0
  10. package/node_modules/graceful-fs/legacy-streams.js +118 -0
  11. package/node_modules/graceful-fs/package.json +53 -0
  12. package/node_modules/graceful-fs/polyfills.js +355 -0
  13. package/node_modules/proper-lockfile/CHANGELOG.md +108 -0
  14. package/node_modules/proper-lockfile/LICENSE +21 -0
  15. package/node_modules/proper-lockfile/README.md +183 -0
  16. package/node_modules/proper-lockfile/index.js +40 -0
  17. package/node_modules/proper-lockfile/lib/adapter.js +85 -0
  18. package/node_modules/proper-lockfile/lib/lockfile.js +342 -0
  19. package/node_modules/proper-lockfile/lib/mtime-precision.js +55 -0
  20. package/node_modules/proper-lockfile/package.json +71 -0
  21. package/node_modules/retry/.npmignore +3 -0
  22. package/node_modules/retry/.travis.yml +15 -0
  23. package/node_modules/retry/License +21 -0
  24. package/node_modules/retry/Makefile +18 -0
  25. package/node_modules/retry/README.md +227 -0
  26. package/node_modules/retry/equation.gif +0 -0
  27. package/node_modules/retry/example/dns.js +31 -0
  28. package/node_modules/retry/example/stop.js +40 -0
  29. package/node_modules/retry/index.js +1 -0
  30. package/node_modules/retry/lib/retry.js +100 -0
  31. package/node_modules/retry/lib/retry_operation.js +158 -0
  32. package/node_modules/retry/package.json +32 -0
  33. package/node_modules/retry/test/common.js +10 -0
  34. package/node_modules/retry/test/integration/test-forever.js +24 -0
  35. package/node_modules/retry/test/integration/test-retry-operation.js +258 -0
  36. package/node_modules/retry/test/integration/test-retry-wrap.js +101 -0
  37. package/node_modules/retry/test/integration/test-timeouts.js +69 -0
  38. package/node_modules/signal-exit/LICENSE.txt +16 -0
  39. package/node_modules/signal-exit/README.md +39 -0
  40. package/node_modules/signal-exit/index.js +202 -0
  41. package/node_modules/signal-exit/package.json +38 -0
  42. package/node_modules/signal-exit/signals.js +53 -0
  43. package/package.json +5 -2
  44. package/skills/taskchef-bootstrap/SKILL.md +2 -3
  45. package/skills/taskchef-delegate/SKILL.md +75 -11
  46. package/skills/taskchef-report/SKILL.md +20 -10
  47. package/src/cli.js +19 -1
  48. package/src/delegation.js +555 -0
  49. package/src/workspace.js +53 -172
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskchef",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "description": "Dispatch work from a data-only workspace to visible Codex project tasks.",
5
5
  "author": {
6
6
  "name": "Favo Yang",
package/BACKLOG.md CHANGED
@@ -39,3 +39,18 @@ clear data model before implementation.
39
39
  - Evaluate automatic project discovery rules and exclusions.
40
40
  - Consider multiple executor threads for one logical assignment if a real
41
41
  workflow requires it.
42
+
43
+ ## Codex provisional thread lifecycle
44
+
45
+ - Track [openai/codex#26861](https://github.com/openai/codex/issues/26861),
46
+ where worktree creation can return only a provisional `clientThreadId` or
47
+ `pendingWorktreeId` with no supported mapping to the durable `threadId`.
48
+ - Prefer an official bounded operation such as
49
+ `wait_for_thread(clientThreadId, timeoutMs) -> { status, threadId? }` or
50
+ `resolve_client_thread(clientThreadId) -> { status, threadId? }`. Returning a
51
+ reserved durable ID from `create_thread`, or emitting a materialization event
52
+ containing it, would also close the lifecycle gap.
53
+ - Re-evaluate TaskChef's sparse marker-discovery fallback when Codex exposes
54
+ one of these APIs. Keep exact marker verification before persisting the
55
+ returned durable ID unless the official contract provides equivalent
56
+ correlation guarantees.
package/README.md CHANGED
@@ -117,9 +117,18 @@ the same project.
117
117
  Open an executor and prompt it like any other Codex task. Its thread is the
118
118
  live source of truth for progress, questions, and results.
119
119
 
120
- The dispatcher workspace keeps `tasks.jsonl`, an append-only history of
121
- successful delegations. It records what TaskChef sent, when it sent it, which
122
- project it selected, and which Codex task received the work.
120
+ The dispatcher workspace keeps `tasks.jsonl`, a history of submitted
121
+ delegations. New tasks are appended; the only later change allowed is filling
122
+ an unresolved task's nullable thread ID. The log records what TaskChef sent,
123
+ when it sent it, which project it selected, and which Codex task received the
124
+ work.
125
+
126
+ Every delegated instruction includes a unique `# taskchef_id=<UUID>` marker.
127
+ If worktree creation does not return a thread ID immediately, TaskChef records
128
+ the marked delegation as unresolved, then waits briefly for the durable task.
129
+ It prefers a native Codex client-ID resolver when available and otherwise makes
130
+ two exact-marker checks during a short bounded window. If it still cannot
131
+ identify exactly one task, the recorded marker remains available for recovery.
123
132
 
124
133
  ### Ask for a live report
125
134
 
@@ -161,8 +170,9 @@ project metadata that TaskChef used when it delegated the work.
161
170
 
162
171
  - TaskChef is an interactive dispatcher. It is not a scheduler, daemon, hook
163
172
  service, or background worker.
164
- - Executors are visible Codex tasks. The dispatcher does not supervise them or
165
- wait for them to finish.
173
+ - Executors are visible Codex tasks. The dispatcher may wait briefly to resolve
174
+ a worktree task's thread ID, but it does not supervise executors or wait for
175
+ them to finish.
166
176
  - TaskChef routes only to projects on the same local execution host.
167
177
  - The task history contains successful delegations, not current task status or
168
178
  task results.
@@ -213,6 +223,7 @@ taskchef project import [<file> | -]
213
223
  taskchef project list
214
224
  taskchef project remove <name>
215
225
  taskchef task record
226
+ taskchef task resolve <task-id> --thread-id <thread-id>
216
227
  taskchef task show <task-id>
217
228
  taskchef task list
218
229
  taskchef task summary
@@ -250,14 +261,24 @@ set.
250
261
 
251
262
  ### Task history
252
263
 
253
- `task record` reads one successful delegation from standard input. The
264
+ `task record` reads one submitted delegation from standard input. The
254
265
  `project` value is the exact configured project path:
255
266
 
256
267
  ```sh
257
- printf '%s\n' '{"id":"t1","project":"/workspace/payments","title":"Add retry logs","instruction":"Add structured logs for failed retries and test them.","threadId":"019f..."}' |
268
+ printf '%s\n' '{"id":"c0f010ff-84f2-4838-a69d-0ff1f5d721d7","project":"/workspace/payments","title":"Add retry logs","instruction":"# taskchef_id=c0f010ff-84f2-4838-a69d-0ff1f5d721d7\n\nAdd structured logs for failed retries and test them.","threadId":"019f..."}' |
258
269
  taskchef task record --json --workspace <workspace>
259
270
  ```
260
271
 
272
+ If a task has `threadId: null`, Codex can later find its exact marker and pass
273
+ the verified durable ID to the CLI. Resolution is atomic and only permits the
274
+ one-way transition from null to one unique thread ID:
275
+
276
+ ```sh
277
+ taskchef task resolve c0f010ff-84f2-4838-a69d-0ff1f5d721d7 \
278
+ --thread-id 019f9d46-f42c-7482-9707-3c107bf241ee \
279
+ --workspace <workspace>
280
+ ```
281
+
261
282
  Inspect the task history without querying Codex tasks:
262
283
 
263
284
  ```sh
package/SPEC.md CHANGED
@@ -3,8 +3,9 @@
3
3
  ## Purpose
4
4
 
5
5
  TaskChef is an interactive Codex dispatcher. It routes independent assignments
6
- to real Codex tasks in configured local projects, records each successful
7
- delegation in an append-only task history, and returns immediately.
6
+ to real Codex tasks in configured local projects, records each submitted
7
+ delegation in a task history, and returns immediately. New tasks append; only a
8
+ nullable thread ID may later transition to its durable value.
8
9
 
9
10
  Codex tasks remain authoritative for their progress and results. TaskChef does
10
11
  not maintain a second lifecycle database.
@@ -16,8 +17,10 @@ not maintain a second lifecycle database.
16
17
  3. It selects each target using configured project metadata and validates the
17
18
  selected local path.
18
19
  4. It creates an independently openable Codex task in that project.
19
- 5. After creation returns a thread ID, it appends one task entry.
20
- 6. It returns without waiting for the executor.
20
+ 5. It embeds a generated TaskChef UUID marker in the initial instruction before
21
+ creation. It appends one task entry as soon as creation returns, using
22
+ `threadId: null` while a provisional client ID is briefly resolved.
23
+ 6. It returns without waiting for executor work to complete.
21
24
  7. When requested, TaskChef can read task entries, query the relevant Codex
22
25
  tasks once, and present a live report without persisting the fetched state.
23
26
 
@@ -38,15 +41,11 @@ live report requests to `$taskchef-report`. Bootstrap preserves unrelated
38
41
  instructions and refreshes only the managed block.
39
42
 
40
43
  `workspace init` is idempotent. It creates an empty configuration and task
41
- log when missing, refreshes managed instructions, removes legacy TaskChef skill
42
- symlinks, and migrates legacy task records that contain executor thread IDs.
43
- It stops on a legacy pending record with no thread ID rather than discarding
44
- that record. If a legacy record refers to a project that was removed from the
45
- configuration, migration reconstructs its project snapshot from the existing
46
- local project path.
44
+ log when missing, refreshes managed instructions, and removes legacy TaskChef
45
+ skill symlinks.
47
46
 
48
47
  `doctor` validates configuration, project paths, the JSONL log, managed
49
- instructions, and the absence of legacy workspace structures without modifying
48
+ instructions, and the absence of legacy TaskChef skill links without modifying
50
49
  the workspace.
51
50
 
52
51
  ## Project configuration
@@ -101,22 +100,30 @@ schedules, task status, results, host information, or the workspace path.
101
100
  `tasks.jsonl` contains one compact JSON object per line, in append order:
102
101
 
103
102
  ```json
104
- {"schemaVersion":1,"id":"d1-retry-logs","project":{"name":"payments-api","path":"/workspace/payments-api","isGitRepository":true,"githubRepo":"https://github.com/example/payments-api","description":"Owns payment authorization, capture, refunds, and provider integrations."},"title":"Add payment retry logs","instruction":"Add structured logs for failed payment retries and test them.","threadId":"019f9d46-f42c-7482-9707-3c107bf241ee","createdAt":"2026-08-08T10:00:00.000Z"}
103
+ {"schemaVersion":1,"id":"c0f010ff-84f2-4838-a69d-0ff1f5d721d7","project":{"name":"payments-api","path":"/workspace/payments-api","isGitRepository":true,"githubRepo":"https://github.com/example/payments-api","description":"Owns payment authorization, capture, refunds, and provider integrations."},"title":"Add payment retry logs","instruction":"# taskchef_id=c0f010ff-84f2-4838-a69d-0ff1f5d721d7\n\nAdd structured logs for failed payment retries and test them.","threadId":"019f9d46-f42c-7482-9707-3c107bf241ee","createdAt":"2026-08-08T10:00:00.000Z"}
105
104
  ```
106
105
 
107
106
  - `schemaVersion` identifies the task entry format.
108
107
  - `id` is a unique TaskChef task identifier.
109
108
  - `project` is the complete configured project snapshot used for routing.
110
109
  - `title` is a short task name.
111
- - `instruction` is the complete executor instruction.
112
- - `threadId` identifies the created Codex task.
110
+ - `instruction` is the complete executor instruction, including its first-line
111
+ `# taskchef_id=<full UUID>` correlation marker.
112
+ - `threadId` identifies the created Codex task, or is `null` when creation was
113
+ accepted but bounded marker resolution did not find one durable task ID.
113
114
  - `createdAt` is the dispatch time as an ISO 8601 timestamp.
114
115
 
115
- Every entry has exactly these fields. IDs and thread IDs must be unique. The
116
- file is empty or newline terminated, with no blank lines. TaskChef rejects a
117
- malformed log instead of skipping bad entries. Writers replace the complete
118
- validated file atomically under a workspace lock, so an interrupted write
119
- leaves either the old history or the complete new history.
116
+ Every entry has exactly these fields. IDs and non-null thread IDs must be
117
+ unique; any number of unresolved entries may have `threadId: null`. The file is
118
+ empty or newline terminated, with no blank lines. TaskChef rejects a malformed
119
+ log instead of skipping bad entries. Writers replace the complete validated
120
+ file atomically under a workspace lock, so an interrupted write leaves either
121
+ the old history or the complete new history.
122
+
123
+ Task creation appends entries. The only permitted mutation is an atomic,
124
+ idempotent `task resolve` transition from `threadId: null` to one unique durable
125
+ thread ID. Resolution requires the stored instruction's exact marker to match
126
+ the task ID. A resolved or mismatched entry cannot be overwritten.
120
127
 
121
128
  The project snapshot preserves the route even if the project is renamed,
122
129
  moved, or removed later. Entries never contain status, result, transcript,
@@ -128,9 +135,41 @@ For each assignment, `$taskchef-delegate`:
128
135
 
129
136
  1. loads and validates configured projects
130
137
  2. selects one unambiguous target
131
- 3. creates a real Codex task at the exact configured path
132
- 4. appends a task entry only after receiving the task's thread ID
133
- 5. returns the created task link without reading or waiting for that task.
138
+ 3. generates a full UUID and prefixes the instruction with its exact
139
+ `# taskchef_id=<UUID>` marker
140
+ 4. creates a real Codex task at the exact configured path
141
+ 5. appends a task entry immediately when creation returns a durable thread ID
142
+ 6. when creation returns only a provisional client ID, immediately appends the
143
+ marked entry with `threadId: null`, then prefers one native client-ID wait or
144
+ resolution call with a 30-second timeout when Codex exposes one
145
+ 7. when no native operation is available, takes at most two recent-thread
146
+ snapshots near 10 and 30 seconds after the provisional result, filters
147
+ candidates by available host/project/time/worktree metadata, uses title only
148
+ as an advisory ordering hint, and accepts only one thread whose structured
149
+ delegated input starts with the exact marker
150
+ 8. atomically fills the nullable thread ID after an exact match
151
+ 9. returns after recording or after reporting that bounded resolution was
152
+ unresolved, without waiting for executor work completion.
153
+
154
+ The exact random marker makes a pre-creation thread snapshot unnecessary.
155
+ Creation-time filtering allows five seconds of clock skew. Candidate reads run
156
+ concurrently where the host permits and inspect only structured
157
+ `codexDelegation.input`, never untrusted title, summary, preview, or plain-text
158
+ marker echoes. A native resolver result is verified against the same structured
159
+ marker before persistence. Zero exact matches time out unresolved; multiple
160
+ exact matches are ambiguous. Snapshot, candidate-read, native-resolution, or
161
+ task-resolution errors leave the already-recorded nullable entry intact. No
162
+ snapshot, candidate read, marker verification, or task-resolution write starts
163
+ after the 30-second deadline, so tool latency can reduce the number of attempts.
164
+ A `clientThreadId`, `pendingWorktreeId`, or ID in the documented provisional
165
+ `local:` namespace remains diagnostic context and is rejected from every path
166
+ that could persist the canonical `threadId` field.
167
+
168
+ Desktop thread tools are available to the Codex skill, not to the standalone
169
+ Node CLI. The package therefore exposes testable marker/filter/orchestration
170
+ helpers with injected thread-tool callbacks, while the skill owns the actual
171
+ desktop-tool calls and the CLI remains responsible only for validated data
172
+ operations.
134
173
 
135
174
  A failed executor creation produces no entry. If executor creation succeeds but
136
175
  the append fails, the executor remains valid and TaskChef tells the user that
@@ -144,19 +183,23 @@ The CLI reads persisted history without contacting Codex:
144
183
  - `task list` returns entries in append order, optionally filtered by
145
184
  historical project name or exact path.
146
185
  - `task summary` returns the total and per-project counts.
186
+ - `task resolve <id> --thread-id <thread-id>` atomically fills one nullable
187
+ thread ID after Codex verifies the exact structured marker match.
147
188
 
148
- When the user requests current state or outcomes, `$taskchef-report` loads the
149
- relevant entries and queries every recorded Codex task exactly once, in batches
150
- of no more than eight. It reports the snapshot and discards it. The report does
151
- not update `tasks.jsonl`, poll, wait, or create a scheduled job.
189
+ When the user requests current state or outcomes, `$taskchef-report` makes one
190
+ marker-based discovery pass for nullable entries and uses `task resolve` only
191
+ for a single exact match. It reports unmatched entries as unresolved and
192
+ queries every durable thread ID exactly once, in batches of no more than eight.
193
+ The report does not poll, wait, persist status or results, or create a scheduled
194
+ job.
152
195
 
153
196
  ## Boundaries
154
197
 
155
198
  TaskChef does not include:
156
199
 
157
200
  - lifecycle status or result persistence
158
- - task callbacks, hooks, polling, daemons, heartbeats, or schedules
159
- - arbitrary Codex task discovery
201
+ - task callbacks, hooks, indefinite polling, daemons, heartbeats, or schedules
202
+ - arbitrary Codex task discovery beyond bounded marker-based creation recovery
160
203
  - remote hosts or `hostId` storage
161
204
  - transcript or hidden-reasoning collection
162
205
  - one-active-task-per-project restrictions
@@ -170,10 +213,13 @@ TaskChef does not include:
170
213
  2. Project metadata routes an unambiguous request to the correct local project.
171
214
  3. A successful delegation creates a visible Codex task and appends its thread
172
215
  ID with a project snapshot.
173
- 4. The dispatcher returns without waiting for execution.
174
- 5. Several independent assignments can create several entries, including
216
+ 4. A provisional creation with one exact marker match records its durable
217
+ thread ID; zero or multiple matches record `threadId: null` for later
218
+ recovery.
219
+ 5. The dispatcher returns without waiting for execution.
220
+ 6. Several independent assignments can create several entries, including
175
221
  multiple entries for the same project.
176
- 6. Task history commands return deterministic entries and project counts.
177
- 7. A live report queries each relevant task once and writes nothing.
178
- 8. Malformed JSONL, duplicate IDs, duplicate thread IDs, and symlinked managed
222
+ 7. Task history commands return deterministic entries and project counts.
223
+ 8. A live report queries each relevant task once and writes nothing.
224
+ 9. Malformed JSONL, duplicate IDs, duplicate thread IDs, and symlinked managed
179
225
  files fail safely.
package/index.js CHANGED
@@ -14,7 +14,25 @@ export {
14
14
  listTasks,
15
15
  readTask,
16
16
  recordTask,
17
+ resolveTask,
17
18
  requireSafeId,
18
19
  removeProject,
19
20
  validateConfig,
20
21
  } from "./src/workspace.js";
22
+
23
+ export {
24
+ THREAD_RESOLUTION_CHECKPOINTS_MS,
25
+ THREAD_RESOLUTION_CLOCK_SKEW_MS,
26
+ THREAD_RESOLUTION_RECENT_LIMIT,
27
+ THREAD_RESOLUTION_TIMEOUT_MS,
28
+ createAndRecordDelegation,
29
+ filterThreadCandidates,
30
+ hasExactTaskChefMarker,
31
+ listThreadEntries,
32
+ isProvisionalThreadId,
33
+ normalizeDurableThreadId,
34
+ parseTaskChefMarker,
35
+ prepareDelegation,
36
+ structuredDelegatedInputs,
37
+ taskChefMarker,
38
+ } from "./src/delegation.js";
@@ -0,0 +1,15 @@
1
+ The ISC License
2
+
3
+ Copyright (c) 2011-2022 Isaac Z. Schlueter, Ben Noordhuis, and Contributors
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
15
+ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
@@ -0,0 +1,143 @@
1
+ # graceful-fs
2
+
3
+ graceful-fs functions as a drop-in replacement for the fs module,
4
+ making various improvements.
5
+
6
+ The improvements are meant to normalize behavior across different
7
+ platforms and environments, and to make filesystem access more
8
+ resilient to errors.
9
+
10
+ ## Improvements over [fs module](https://nodejs.org/api/fs.html)
11
+
12
+ * Queues up `open` and `readdir` calls, and retries them once
13
+ something closes if there is an EMFILE error from too many file
14
+ descriptors.
15
+ * fixes `lchmod` for Node versions prior to 0.6.2.
16
+ * implements `fs.lutimes` if possible. Otherwise it becomes a noop.
17
+ * ignores `EINVAL` and `EPERM` errors in `chown`, `fchown` or
18
+ `lchown` if the user isn't root.
19
+ * makes `lchmod` and `lchown` become noops, if not available.
20
+ * retries reading a file if `read` results in EAGAIN error.
21
+
22
+ On Windows, it retries renaming a file for up to one second if `EACCESS`
23
+ or `EPERM` error occurs, likely because antivirus software has locked
24
+ the directory.
25
+
26
+ ## USAGE
27
+
28
+ ```javascript
29
+ // use just like fs
30
+ var fs = require('graceful-fs')
31
+
32
+ // now go and do stuff with it...
33
+ fs.readFile('some-file-or-whatever', (err, data) => {
34
+ // Do stuff here.
35
+ })
36
+ ```
37
+
38
+ ## Sync methods
39
+
40
+ This module cannot intercept or handle `EMFILE` or `ENFILE` errors from sync
41
+ methods. If you use sync methods which open file descriptors then you are
42
+ responsible for dealing with any errors.
43
+
44
+ This is a known limitation, not a bug.
45
+
46
+ ## Global Patching
47
+
48
+ If you want to patch the global fs module (or any other fs-like
49
+ module) you can do this:
50
+
51
+ ```javascript
52
+ // Make sure to read the caveat below.
53
+ var realFs = require('fs')
54
+ var gracefulFs = require('graceful-fs')
55
+ gracefulFs.gracefulify(realFs)
56
+ ```
57
+
58
+ This should only ever be done at the top-level application layer, in
59
+ order to delay on EMFILE errors from any fs-using dependencies. You
60
+ should **not** do this in a library, because it can cause unexpected
61
+ delays in other parts of the program.
62
+
63
+ ## Changes
64
+
65
+ This module is fairly stable at this point, and used by a lot of
66
+ things. That being said, because it implements a subtle behavior
67
+ change in a core part of the node API, even modest changes can be
68
+ extremely breaking, and the versioning is thus biased towards
69
+ bumping the major when in doubt.
70
+
71
+ The main change between major versions has been switching between
72
+ providing a fully-patched `fs` module vs monkey-patching the node core
73
+ builtin, and the approach by which a non-monkey-patched `fs` was
74
+ created.
75
+
76
+ The goal is to trade `EMFILE` errors for slower fs operations. So, if
77
+ you try to open a zillion files, rather than crashing, `open`
78
+ operations will be queued up and wait for something else to `close`.
79
+
80
+ There are advantages to each approach. Monkey-patching the fs means
81
+ that no `EMFILE` errors can possibly occur anywhere in your
82
+ application, because everything is using the same core `fs` module,
83
+ which is patched. However, it can also obviously cause undesirable
84
+ side-effects, especially if the module is loaded multiple times.
85
+
86
+ Implementing a separate-but-identical patched `fs` module is more
87
+ surgical (and doesn't run the risk of patching multiple times), but
88
+ also imposes the challenge of keeping in sync with the core module.
89
+
90
+ The current approach loads the `fs` module, and then creates a
91
+ lookalike object that has all the same methods, except a few that are
92
+ patched. It is safe to use in all versions of Node from 0.8 through
93
+ 7.0.
94
+
95
+ ### v4
96
+
97
+ * Do not monkey-patch the fs module. This module may now be used as a
98
+ drop-in dep, and users can opt into monkey-patching the fs builtin
99
+ if their app requires it.
100
+
101
+ ### v3
102
+
103
+ * Monkey-patch fs, because the eval approach no longer works on recent
104
+ node.
105
+ * fixed possible type-error throw if rename fails on windows
106
+ * verify that we *never* get EMFILE errors
107
+ * Ignore ENOSYS from chmod/chown
108
+ * clarify that graceful-fs must be used as a drop-in
109
+
110
+ ### v2.1.0
111
+
112
+ * Use eval rather than monkey-patching fs.
113
+ * readdir: Always sort the results
114
+ * win32: requeue a file if error has an OK status
115
+
116
+ ### v2.0
117
+
118
+ * A return to monkey patching
119
+ * wrap process.cwd
120
+
121
+ ### v1.1
122
+
123
+ * wrap readFile
124
+ * Wrap fs.writeFile.
125
+ * readdir protection
126
+ * Don't clobber the fs builtin
127
+ * Handle fs.read EAGAIN errors by trying again
128
+ * Expose the curOpen counter
129
+ * No-op lchown/lchmod if not implemented
130
+ * fs.rename patch only for win32
131
+ * Patch fs.rename to handle AV software on Windows
132
+ * Close #4 Chown should not fail on einval or eperm if non-root
133
+ * Fix isaacs/fstream#1 Only wrap fs one time
134
+ * Fix #3 Start at 1024 max files, then back off on EMFILE
135
+ * lutimes that doens't blow up on Linux
136
+ * A full on-rewrite using a queue instead of just swallowing the EMFILE error
137
+ * Wrap Read/Write streams as well
138
+
139
+ ### 1.0
140
+
141
+ * Update engines for node 0.6
142
+ * Be lstat-graceful on Windows
143
+ * first
@@ -0,0 +1,23 @@
1
+ 'use strict'
2
+
3
+ module.exports = clone
4
+
5
+ var getPrototypeOf = Object.getPrototypeOf || function (obj) {
6
+ return obj.__proto__
7
+ }
8
+
9
+ function clone (obj) {
10
+ if (obj === null || typeof obj !== 'object')
11
+ return obj
12
+
13
+ if (obj instanceof Object)
14
+ var copy = { __proto__: getPrototypeOf(obj) }
15
+ else
16
+ var copy = Object.create(null)
17
+
18
+ Object.getOwnPropertyNames(obj).forEach(function (key) {
19
+ Object.defineProperty(copy, key, Object.getOwnPropertyDescriptor(obj, key))
20
+ })
21
+
22
+ return copy
23
+ }