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.
- package/.codex-plugin/plugin.json +1 -1
- package/BACKLOG.md +15 -0
- package/README.md +28 -7
- package/SPEC.md +79 -33
- package/index.js +18 -0
- package/node_modules/graceful-fs/LICENSE +15 -0
- package/node_modules/graceful-fs/README.md +143 -0
- package/node_modules/graceful-fs/clone.js +23 -0
- package/node_modules/graceful-fs/graceful-fs.js +448 -0
- package/node_modules/graceful-fs/legacy-streams.js +118 -0
- package/node_modules/graceful-fs/package.json +53 -0
- package/node_modules/graceful-fs/polyfills.js +355 -0
- package/node_modules/proper-lockfile/CHANGELOG.md +108 -0
- package/node_modules/proper-lockfile/LICENSE +21 -0
- package/node_modules/proper-lockfile/README.md +183 -0
- package/node_modules/proper-lockfile/index.js +40 -0
- package/node_modules/proper-lockfile/lib/adapter.js +85 -0
- package/node_modules/proper-lockfile/lib/lockfile.js +342 -0
- package/node_modules/proper-lockfile/lib/mtime-precision.js +55 -0
- package/node_modules/proper-lockfile/package.json +71 -0
- package/node_modules/retry/.npmignore +3 -0
- package/node_modules/retry/.travis.yml +15 -0
- package/node_modules/retry/License +21 -0
- package/node_modules/retry/Makefile +18 -0
- package/node_modules/retry/README.md +227 -0
- package/node_modules/retry/equation.gif +0 -0
- package/node_modules/retry/example/dns.js +31 -0
- package/node_modules/retry/example/stop.js +40 -0
- package/node_modules/retry/index.js +1 -0
- package/node_modules/retry/lib/retry.js +100 -0
- package/node_modules/retry/lib/retry_operation.js +158 -0
- package/node_modules/retry/package.json +32 -0
- package/node_modules/retry/test/common.js +10 -0
- package/node_modules/retry/test/integration/test-forever.js +24 -0
- package/node_modules/retry/test/integration/test-retry-operation.js +258 -0
- package/node_modules/retry/test/integration/test-retry-wrap.js +101 -0
- package/node_modules/retry/test/integration/test-timeouts.js +69 -0
- package/node_modules/signal-exit/LICENSE.txt +16 -0
- package/node_modules/signal-exit/README.md +39 -0
- package/node_modules/signal-exit/index.js +202 -0
- package/node_modules/signal-exit/package.json +38 -0
- package/node_modules/signal-exit/signals.js +53 -0
- package/package.json +5 -2
- package/skills/taskchef-bootstrap/SKILL.md +2 -3
- package/skills/taskchef-delegate/SKILL.md +75 -11
- package/skills/taskchef-report/SKILL.md +20 -10
- package/src/cli.js +19 -1
- package/src/delegation.js +555 -0
- package/src/workspace.js +53 -172
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`,
|
|
121
|
-
|
|
122
|
-
|
|
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
|
|
165
|
-
|
|
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
|
|
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":"
|
|
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
|
|
7
|
-
delegation in
|
|
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.
|
|
20
|
-
|
|
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
|
|
42
|
-
symlinks
|
|
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
|
|
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":"
|
|
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
|
-
|
|
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
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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.
|
|
132
|
-
|
|
133
|
-
|
|
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`
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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.
|
|
174
|
-
|
|
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
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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
|
+
}
|